1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle in the LICENSE file that accompanied this code. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 /* 27 * 28 * (C) Copyright IBM Corp. 1998-2009 - All Rights Reserved 29 * 30 */ 31 32 #include "LETypes.h" 33 #include "OpenTypeTables.h" 34 #include "OpenTypeUtilities.h" 35 #include "IndicReordering.h" 36 #include "LEGlyphStorage.h" 37 #include "MPreFixups.h" 38 39 U_NAMESPACE_BEGIN 40 41 #define loclFeatureTag LE_LOCL_FEATURE_TAG 42 #define initFeatureTag LE_INIT_FEATURE_TAG 43 #define nuktFeatureTag LE_NUKT_FEATURE_TAG 44 #define akhnFeatureTag LE_AKHN_FEATURE_TAG 45 #define rphfFeatureTag LE_RPHF_FEATURE_TAG 46 #define rkrfFeatureTag LE_RKRF_FEATURE_TAG 47 #define blwfFeatureTag LE_BLWF_FEATURE_TAG 48 #define halfFeatureTag LE_HALF_FEATURE_TAG 49 #define pstfFeatureTag LE_PSTF_FEATURE_TAG 50 #define vatuFeatureTag LE_VATU_FEATURE_TAG 51 #define presFeatureTag LE_PRES_FEATURE_TAG 52 #define blwsFeatureTag LE_BLWS_FEATURE_TAG 53 #define abvsFeatureTag LE_ABVS_FEATURE_TAG 54 #define pstsFeatureTag LE_PSTS_FEATURE_TAG 55 #define halnFeatureTag LE_HALN_FEATURE_TAG 56 #define cjctFeatureTag LE_CJCT_FEATURE_TAG 57 #define blwmFeatureTag LE_BLWM_FEATURE_TAG 58 #define abvmFeatureTag LE_ABVM_FEATURE_TAG 59 #define distFeatureTag LE_DIST_FEATURE_TAG 60 #define caltFeatureTag LE_CALT_FEATURE_TAG 61 #define kernFeatureTag LE_KERN_FEATURE_TAG 62 63 #define loclFeatureMask 0x80000000UL 64 #define rphfFeatureMask 0x40000000UL 65 #define blwfFeatureMask 0x20000000UL 66 #define halfFeatureMask 0x10000000UL 67 #define pstfFeatureMask 0x08000000UL 68 #define nuktFeatureMask 0x04000000UL 69 #define akhnFeatureMask 0x02000000UL 70 #define vatuFeatureMask 0x01000000UL 71 #define presFeatureMask 0x00800000UL 72 #define blwsFeatureMask 0x00400000UL 73 #define abvsFeatureMask 0x00200000UL 74 #define pstsFeatureMask 0x00100000UL 75 #define halnFeatureMask 0x00080000UL 76 #define blwmFeatureMask 0x00040000UL 77 #define abvmFeatureMask 0x00020000UL 78 #define distFeatureMask 0x00010000UL 79 #define initFeatureMask 0x00008000UL 80 #define cjctFeatureMask 0x00004000UL 81 #define rkrfFeatureMask 0x00002000UL 82 #define caltFeatureMask 0x00001000UL 83 #define kernFeatureMask 0x00000800UL 84 85 // Syllable structure bits 86 #define baseConsonantMask 0x00000400UL 87 #define consonantMask 0x00000200UL 88 #define halfConsonantMask 0x00000100UL 89 #define rephConsonantMask 0x00000080UL 90 #define matraMask 0x00000040UL 91 #define vowelModifierMask 0x00000020UL 92 #define markPositionMask 0x00000018UL 93 94 #define postBasePosition 0x00000000UL 95 #define preBasePosition 0x00000008UL 96 #define aboveBasePosition 0x00000010UL 97 #define belowBasePosition 0x00000018UL 98 99 #define repositionedGlyphMask 0x00000002UL 100 101 #define basicShapingFormsMask ( loclFeatureMask | nuktFeatureMask | akhnFeatureMask | rkrfFeatureMask | blwfFeatureMask | halfFeatureMask | vatuFeatureMask | cjctFeatureMask ) 102 #define positioningFormsMask ( kernFeatureMask | distFeatureMask | abvmFeatureMask | blwmFeatureMask ) 103 #define presentationFormsMask ( presFeatureMask | abvsFeatureMask | blwsFeatureMask | pstsFeatureMask | halnFeatureMask | caltFeatureMask ) 104 105 106 #define C_MALAYALAM_VOWEL_SIGN_U 0x0D41 107 #define C_DOTTED_CIRCLE 0x25CC 108 #define NO_GLYPH 0xFFFF 109 110 // Some level of debate as to the proper value for MAX_CONSONANTS_PER_SYLLABLE. Ticket 5588 states that 4 111 // is the magic number according to ISCII, but 5 seems to be the more consistent with XP. 112 #define MAX_CONSONANTS_PER_SYLLABLE 5 113 114 #define INDIC_BLOCK_SIZE 0x7F 115 116 class IndicReorderingOutput : public UMemory { 117 private: 118 le_int32 fSyllableCount; 119 le_int32 fOutIndex; 120 LEUnicode *fOutChars; 121 122 LEGlyphStorage &fGlyphStorage; 123 124 LEUnicode fMpre; 125 le_int32 fMpreIndex; 126 127 LEUnicode fMbelow; 128 le_int32 fMbelowIndex; 129 130 LEUnicode fMabove; 131 le_int32 fMaboveIndex; 132 133 LEUnicode fMpost; 134 le_int32 fMpostIndex; 135 136 LEUnicode fLengthMark; 137 le_int32 fLengthMarkIndex; 138 139 LEUnicode fAlLakuna; 140 le_int32 fAlLakunaIndex; 141 142 FeatureMask fMatraFeatures; 143 144 le_int32 fMPreOutIndex; 145 MPreFixups *fMPreFixups; 146 147 LEUnicode fVMabove; 148 LEUnicode fVMpost; 149 le_int32 fVMIndex; 150 FeatureMask fVMFeatures; 151 152 LEUnicode fSMabove; 153 LEUnicode fSMbelow; 154 le_int32 fSMIndex; 155 FeatureMask fSMFeatures; 156 157 LEUnicode fPreBaseConsonant; 158 LEUnicode fPreBaseVirama; 159 le_int32 fPBCIndex; 160 FeatureMask fPBCFeatures; 161 162 void saveMatra(LEUnicode matra, le_int32 matraIndex, IndicClassTable::CharClass matraClass) 163 { 164 // FIXME: check if already set, or if not a matra... 165 if (IndicClassTable::isLengthMark(matraClass)) { 166 fLengthMark = matra; 167 fLengthMarkIndex = matraIndex; 168 } else if (IndicClassTable::isAlLakuna(matraClass)) { 169 fAlLakuna = matra; 170 fAlLakunaIndex = matraIndex; 171 } else { 172 switch (matraClass & CF_POS_MASK) { 173 case CF_POS_BEFORE: 174 fMpre = matra; 175 fMpreIndex = matraIndex; 176 break; 177 178 case CF_POS_BELOW: 179 fMbelow = matra; 180 fMbelowIndex = matraIndex; 181 break; 182 183 case CF_POS_ABOVE: 184 fMabove = matra; 185 fMaboveIndex = matraIndex; 186 break; 187 188 case CF_POS_AFTER: 189 fMpost = matra; 190 fMpostIndex = matraIndex; 191 break; 192 193 default: 194 // can't get here... 195 break; 196 } 197 } 198 } 199 200 public: 201 IndicReorderingOutput(LEUnicode *outChars, LEGlyphStorage &glyphStorage, MPreFixups *mpreFixups) 202 : fSyllableCount(0), fOutIndex(0), fOutChars(outChars), fGlyphStorage(glyphStorage), 203 fMpre(0), fMpreIndex(0), fMbelow(0), fMbelowIndex(0), fMabove(0), fMaboveIndex(0), 204 fMpost(0), fMpostIndex(0), fLengthMark(0), fLengthMarkIndex(0), fAlLakuna(0), fAlLakunaIndex(0), 205 fMatraFeatures(0), fMPreOutIndex(-1), fMPreFixups(mpreFixups), 206 fVMabove(0), fVMpost(0), fVMIndex(0), fVMFeatures(0), 207 fSMabove(0), fSMbelow(0), fSMIndex(0), fSMFeatures(0), 208 fPreBaseConsonant(0), fPreBaseVirama(0), fPBCIndex(0), fPBCFeatures(0) 209 { 210 // nothing else to do... 211 } 212 213 ~IndicReorderingOutput() 214 { 215 // nothing to do here... 216 } 217 218 void reset() 219 { 220 fSyllableCount += 1; 221 222 fMpre = fMbelow = fMabove = fMpost = fLengthMark = fAlLakuna = 0; 223 fMPreOutIndex = -1; 224 225 fVMabove = fVMpost = 0; 226 fSMabove = fSMbelow = 0; 227 228 fPreBaseConsonant = fPreBaseVirama = 0; 229 } 230 231 void writeChar(LEUnicode ch, le_uint32 charIndex, FeatureMask charFeatures) 232 { 233 LEErrorCode success = LE_NO_ERROR; 234 235 fOutChars[fOutIndex] = ch; 236 237 fGlyphStorage.setCharIndex(fOutIndex, charIndex, success); 238 fGlyphStorage.setAuxData(fOutIndex, charFeatures | (fSyllableCount & LE_GLYPH_GROUP_MASK), success); 239 240 fOutIndex += 1; 241 } 242 243 void setFeatures ( le_uint32 charIndex, FeatureMask charFeatures) 244 { 245 LEErrorCode success = LE_NO_ERROR; 246 247 fGlyphStorage.setAuxData( charIndex, charFeatures, success ); 248 249 } 250 251 FeatureMask getFeatures ( le_uint32 charIndex ) 252 { 253 LEErrorCode success = LE_NO_ERROR; 254 return fGlyphStorage.getAuxData(charIndex,success); 255 } 256 257 void decomposeReorderMatras ( const IndicClassTable *classTable, le_int32 beginSyllable, le_int32 nextSyllable, le_int32 inv_count ) { 258 le_int32 i; 259 LEErrorCode success = LE_NO_ERROR; 260 261 for ( i = beginSyllable ; i < nextSyllable ; i++ ) { 262 if ( classTable->isMatra(fOutChars[i+inv_count])) { 263 IndicClassTable::CharClass matraClass = classTable->getCharClass(fOutChars[i+inv_count]); 264 if ( classTable->isSplitMatra(matraClass)) { 265 le_int32 saveIndex = fGlyphStorage.getCharIndex(i+inv_count,success); 266 le_uint32 saveAuxData = fGlyphStorage.getAuxData(i+inv_count,success); 267 const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass); 268 int j; 269 for (j = 0 ; j < SM_MAX_PIECES && *(splitMatra)[j] != 0 ; j++) { 270 LEUnicode piece = (*splitMatra)[j]; 271 if ( j == 0 ) { 272 fOutChars[i+inv_count] = piece; 273 matraClass = classTable->getCharClass(piece); 274 } else { 275 insertCharacter(piece,i+1+inv_count,saveIndex,saveAuxData); 276 nextSyllable++; 277 } 278 } 279 } 280 281 if ((matraClass & CF_POS_MASK) == CF_POS_BEFORE) { 282 moveCharacter(i+inv_count,beginSyllable+inv_count); 283 } 284 } 285 } 286 } 287 288 void moveCharacter( le_int32 fromPosition, le_int32 toPosition ) { 289 le_int32 i,saveIndex; 290 le_uint32 saveAuxData; 291 LEUnicode saveChar = fOutChars[fromPosition]; 292 LEErrorCode success = LE_NO_ERROR; 293 LEErrorCode success2 = LE_NO_ERROR; 294 saveIndex = fGlyphStorage.getCharIndex(fromPosition,success); 295 saveAuxData = fGlyphStorage.getAuxData(fromPosition,success); 296 297 if ( fromPosition > toPosition ) { 298 for ( i = fromPosition ; i > toPosition ; i-- ) { 299 fOutChars[i] = fOutChars[i-1]; 300 fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i-1,success2),success); 301 fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i-1,success2), success); 302 303 } 304 } else { 305 for ( i = fromPosition ; i < toPosition ; i++ ) { 306 fOutChars[i] = fOutChars[i+1]; 307 fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i+1,success2),success); 308 fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i+1,success2), success); 309 } 310 311 } 312 fOutChars[toPosition] = saveChar; 313 fGlyphStorage.setCharIndex(toPosition,saveIndex,success); 314 fGlyphStorage.setAuxData(toPosition,saveAuxData,success); 315 316 } 317 void insertCharacter( LEUnicode ch, le_int32 toPosition, le_int32 charIndex, le_uint32 auxData ) { 318 LEErrorCode success = LE_NO_ERROR; 319 le_int32 i; 320 fOutIndex += 1; 321 322 for ( i = fOutIndex ; i > toPosition ; i--) { 323 fOutChars[i] = fOutChars[i-1]; 324 fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i-1,success),success); 325 fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i-1,success), success); 326 } 327 328 fOutChars[toPosition] = ch; 329 fGlyphStorage.setCharIndex(toPosition,charIndex,success); 330 fGlyphStorage.setAuxData(toPosition,auxData,success); 331 332 } 333 void removeCharacter( le_int32 fromPosition ) { 334 LEErrorCode success = LE_NO_ERROR; 335 le_int32 i; 336 fOutIndex -= 1; 337 338 for ( i = fromPosition ; i < fOutIndex ; i--) { 339 fOutChars[i] = fOutChars[i+1]; 340 fGlyphStorage.setCharIndex(i,fGlyphStorage.getCharIndex(i+1,success),success); 341 fGlyphStorage.setAuxData(i,fGlyphStorage.getAuxData(i+1,success), success); 342 } 343 } 344 345 le_bool noteMatra(const IndicClassTable *classTable, LEUnicode matra, le_uint32 matraIndex, FeatureMask matraFeatures, le_bool wordStart) 346 { 347 IndicClassTable::CharClass matraClass = classTable->getCharClass(matra); 348 349 fMatraFeatures = matraFeatures; 350 351 if (wordStart) { 352 fMatraFeatures |= initFeatureMask; 353 } 354 355 if (IndicClassTable::isMatra(matraClass)) { 356 if (IndicClassTable::isSplitMatra(matraClass)) { 357 const SplitMatra *splitMatra = classTable->getSplitMatra(matraClass); 358 int i; 359 360 for (i = 0; i < SM_MAX_PIECES && (*splitMatra)[i] != 0; i += 1) { 361 LEUnicode piece = (*splitMatra)[i]; 362 IndicClassTable::CharClass pieceClass = classTable->getCharClass(piece); 363 364 saveMatra(piece, matraIndex, pieceClass); 365 } 366 } else { 367 saveMatra(matra, matraIndex, matraClass); 368 } 369 370 return TRUE; 371 } 372 373 return FALSE; 374 } 375 376 void noteVowelModifier(const IndicClassTable *classTable, LEUnicode vowelModifier, le_uint32 vowelModifierIndex, FeatureMask vowelModifierFeatures) 377 { 378 IndicClassTable::CharClass vmClass = classTable->getCharClass(vowelModifier); 379 380 fVMIndex = vowelModifierIndex; 381 fVMFeatures = vowelModifierFeatures; 382 383 if (IndicClassTable::isVowelModifier(vmClass)) { 384 switch (vmClass & CF_POS_MASK) { 385 case CF_POS_ABOVE: 386 fVMabove = vowelModifier; 387 break; 388 389 case CF_POS_AFTER: 390 fVMpost = vowelModifier; 391 break; 392 393 default: 394 // FIXME: this is an error... 395 break; 396 } 397 } 398 } 399 400 void noteStressMark(const IndicClassTable *classTable, LEUnicode stressMark, le_uint32 stressMarkIndex, FeatureMask stressMarkFeatures) 401 { 402 IndicClassTable::CharClass smClass = classTable->getCharClass(stressMark); 403 404 fSMIndex = stressMarkIndex; 405 fSMFeatures = stressMarkFeatures; 406 407 if (IndicClassTable::isStressMark(smClass)) { 408 switch (smClass & CF_POS_MASK) { 409 case CF_POS_ABOVE: 410 fSMabove = stressMark; 411 break; 412 413 case CF_POS_BELOW: 414 fSMbelow = stressMark; 415 break; 416 417 default: 418 // FIXME: this is an error... 419 break; 420 } 421 } 422 } 423 424 void notePreBaseConsonant(le_uint32 index,LEUnicode PBConsonant, LEUnicode PBVirama, FeatureMask features) 425 { 426 fPBCIndex = index; 427 fPreBaseConsonant = PBConsonant; 428 fPreBaseVirama = PBVirama; 429 fPBCFeatures = features; 430 } 431 432 void noteBaseConsonant() 433 { 434 if (fMPreFixups != NULL && fMPreOutIndex >= 0) { 435 fMPreFixups->add(fOutIndex, fMPreOutIndex); 436 } 437 } 438 439 // Handles Al-Lakuna in Sinhala split vowels. 440 void writeAlLakuna() 441 { 442 if (fAlLakuna != 0) { 443 writeChar(fAlLakuna, fAlLakunaIndex, fMatraFeatures); 444 } 445 } 446 447 void writeMpre() 448 { 449 if (fMpre != 0) { 450 fMPreOutIndex = fOutIndex; 451 writeChar(fMpre, fMpreIndex, fMatraFeatures); 452 } 453 } 454 455 void writeMbelow() 456 { 457 if (fMbelow != 0) { 458 writeChar(fMbelow, fMbelowIndex, fMatraFeatures); 459 } 460 } 461 462 void writeMabove() 463 { 464 if (fMabove != 0) { 465 writeChar(fMabove, fMaboveIndex, fMatraFeatures); 466 } 467 } 468 469 void writeMpost() 470 { 471 if (fMpost != 0) { 472 writeChar(fMpost, fMpostIndex, fMatraFeatures); 473 } 474 } 475 476 void writeLengthMark() 477 { 478 if (fLengthMark != 0) { 479 writeChar(fLengthMark, fLengthMarkIndex, fMatraFeatures); 480 } 481 } 482 483 void writeVMabove() 484 { 485 if (fVMabove != 0) { 486 writeChar(fVMabove, fVMIndex, fVMFeatures); 487 } 488 } 489 490 void writeVMpost() 491 { 492 if (fVMpost != 0) { 493 writeChar(fVMpost, fVMIndex, fVMFeatures); 494 } 495 } 496 497 void writeSMabove() 498 { 499 if (fSMabove != 0) { 500 writeChar(fSMabove, fSMIndex, fSMFeatures); 501 } 502 } 503 504 void writeSMbelow() 505 { 506 if (fSMbelow != 0) { 507 writeChar(fSMbelow, fSMIndex, fSMFeatures); 508 } 509 } 510 511 void writePreBaseConsonant() 512 { 513 // The TDIL spec says that consonant + virama + RRA should produce a rakar in Malayalam. However, 514 // it seems that almost none of the fonts for Malayalam are set up to handle this. 515 // So, we're going to force the issue here by using the rakar as defined with RA in most fonts. 516 517 if (fPreBaseConsonant == 0x0d31) { // RRA 518 fPreBaseConsonant = 0x0d30; // RA 519 } 520 521 if (fPreBaseConsonant != 0) { 522 writeChar(fPreBaseConsonant, fPBCIndex, fPBCFeatures); 523 writeChar(fPreBaseVirama,fPBCIndex-1,fPBCFeatures); 524 } 525 } 526 527 le_int32 getOutputIndex() 528 { 529 return fOutIndex; 530 } 531 }; 532 533 534 535 // TODO: Find better names for these! 536 #define tagArray4 (loclFeatureMask | nuktFeatureMask | akhnFeatureMask | vatuFeatureMask | presFeatureMask | blwsFeatureMask | abvsFeatureMask | pstsFeatureMask | halnFeatureMask | blwmFeatureMask | abvmFeatureMask | distFeatureMask) 537 #define tagArray3 (pstfFeatureMask | tagArray4) 538 #define tagArray2 (halfFeatureMask | tagArray3) 539 #define tagArray1 (blwfFeatureMask | tagArray2) 540 #define tagArray0 (rphfFeatureMask | tagArray1) 541 542 static const FeatureMap featureMap[] = { 543 {loclFeatureTag, loclFeatureMask}, 544 {initFeatureTag, initFeatureMask}, 545 {nuktFeatureTag, nuktFeatureMask}, 546 {akhnFeatureTag, akhnFeatureMask}, 547 {rphfFeatureTag, rphfFeatureMask}, 548 {blwfFeatureTag, blwfFeatureMask}, 549 {halfFeatureTag, halfFeatureMask}, 550 {pstfFeatureTag, pstfFeatureMask}, 551 {vatuFeatureTag, vatuFeatureMask}, 552 {presFeatureTag, presFeatureMask}, 553 {blwsFeatureTag, blwsFeatureMask}, 554 {abvsFeatureTag, abvsFeatureMask}, 555 {pstsFeatureTag, pstsFeatureMask}, 556 {halnFeatureTag, halnFeatureMask}, 557 {blwmFeatureTag, blwmFeatureMask}, 558 {abvmFeatureTag, abvmFeatureMask}, 559 {distFeatureTag, distFeatureMask} 560 }; 561 562 static const le_int32 featureCount = LE_ARRAY_SIZE(featureMap); 563 564 static const FeatureMap v2FeatureMap[] = { 565 {loclFeatureTag, loclFeatureMask}, 566 {nuktFeatureTag, nuktFeatureMask}, 567 {akhnFeatureTag, akhnFeatureMask}, 568 {rphfFeatureTag, rphfFeatureMask}, 569 {rkrfFeatureTag, rkrfFeatureMask}, 570 {blwfFeatureTag, blwfFeatureMask}, 571 {halfFeatureTag, halfFeatureMask}, 572 {vatuFeatureTag, vatuFeatureMask}, 573 {cjctFeatureTag, cjctFeatureMask}, 574 {presFeatureTag, presFeatureMask}, 575 {abvsFeatureTag, abvsFeatureMask}, 576 {blwsFeatureTag, blwsFeatureMask}, 577 {pstsFeatureTag, pstsFeatureMask}, 578 {halnFeatureTag, halnFeatureMask}, 579 {caltFeatureTag, caltFeatureMask}, 580 {kernFeatureTag, kernFeatureMask}, 581 {distFeatureTag, distFeatureMask}, 582 {abvmFeatureTag, abvmFeatureMask}, 583 {blwmFeatureTag, blwmFeatureMask} 584 }; 585 586 static const le_int32 v2FeatureMapCount = LE_ARRAY_SIZE(v2FeatureMap); 587 588 static const le_int8 stateTable[][CC_COUNT] = 589 { 590 // xx vm sm iv i2 i3 ct cn nu dv s1 s2 s3 vr zw al 591 { 1, 6, 1, 5, 8, 11, 3, 2, 1, 5, 9, 5, 5, 1, 1, 1}, // 0 - ground state 592 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 1 - exit state 593 {-1, 6, 1, -1, -1, -1, -1, -1, -1, 5, 9, 5, 5, 4, 12, -1}, // 2 - consonant with nukta 594 {-1, 6, 1, -1, -1, -1, -1, -1, 2, 5, 9, 5, 5, 4, 12, 13}, // 3 - consonant 595 {-1, -1, -1, -1, -1, -1, 3, 2, -1, -1, -1, -1, -1, -1, 7, -1}, // 4 - consonant virama 596 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 5 - dependent vowels 597 {-1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 6 - vowel mark 598 {-1, -1, -1, -1, -1, -1, 3, 2, -1, -1, -1, -1, -1, -1, -1, -1}, // 7 - consonant virama ZWJ, consonant ZWJ virama 599 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1}, // 8 - independent vowels that can take a virama 600 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 5, -1, -1, -1}, // 9 - first part of split vowel 601 {-1, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1}, // 10 - second part of split vowel 602 {-1, 6, 1, -1, -1, -1, -1, -1, -1, 5, 9, 5, 5, 4, -1, -1}, // 11 - independent vowels that can take an iv 603 {-1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, 7}, // 12 - consonant ZWJ (TODO: Take everything else that can be after a consonant?) 604 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1} // 13 - consonant al-lakuna ZWJ consonant 605 }; 606 607 608 const FeatureMap *IndicReordering::getFeatureMap(le_int32 &count) 609 { 610 count = featureCount; 611 612 return featureMap; 613 } 614 615 const FeatureMap *IndicReordering::getv2FeatureMap(le_int32 &count) 616 { 617 count = v2FeatureMapCount; 618 619 return v2FeatureMap; 620 } 621 622 le_int32 IndicReordering::findSyllable(const IndicClassTable *classTable, const LEUnicode *chars, le_int32 prev, le_int32 charCount) 623 { 624 le_int32 cursor = prev; 625 le_int8 state = 0; 626 le_int8 consonant_count = 0; 627 628 while (cursor < charCount) { 629 IndicClassTable::CharClass charClass = classTable->getCharClass(chars[cursor]); 630 631 if ( IndicClassTable::isConsonant(charClass) ) { 632 consonant_count++; 633 if ( consonant_count > MAX_CONSONANTS_PER_SYLLABLE ) { 634 break; 635 } 636 } 637 638 state = stateTable[state][charClass & CF_CLASS_MASK]; 639 640 if (state < 0) { 641 break; 642 } 643 644 cursor += 1; 645 } 646 647 return cursor; 648 } 649 650 le_int32 IndicReordering::reorder(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode, 651 LEUnicode *outChars, LEGlyphStorage &glyphStorage, 652 MPreFixups **outMPreFixups, LEErrorCode& success) 653 { 654 if (LE_FAILURE(success)) { 655 return 0; 656 } 657 658 MPreFixups *mpreFixups = NULL; 659 const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode); 660 661 if(classTable==NULL) { 662 success = LE_MEMORY_ALLOCATION_ERROR; 663 return 0; 664 } 665 666 if (classTable->scriptFlags & SF_MPRE_FIXUP) { 667 mpreFixups = new MPreFixups(charCount); 668 if (mpreFixups == NULL) { 669 success = LE_MEMORY_ALLOCATION_ERROR; 670 return 0; 671 } 672 } 673 674 IndicReorderingOutput output(outChars, glyphStorage, mpreFixups); 675 le_int32 i, prev = 0; 676 le_bool lastInWord = FALSE; 677 678 while (prev < charCount) { 679 le_int32 syllable = findSyllable(classTable, chars, prev, charCount); 680 le_int32 matra, markStart = syllable; 681 682 output.reset(); 683 684 if (classTable->isStressMark(chars[markStart - 1])) { 685 markStart -= 1; 686 output.noteStressMark(classTable, chars[markStart], markStart, tagArray1); 687 } 688 689 if (markStart != prev && classTable->isVowelModifier(chars[markStart - 1])) { 690 markStart -= 1; 691 output.noteVowelModifier(classTable, chars[markStart], markStart, tagArray1); 692 } 693 694 matra = markStart - 1; 695 696 while (output.noteMatra(classTable, chars[matra], matra, tagArray1, !lastInWord) && matra != prev) { 697 matra -= 1; 698 } 699 700 lastInWord = TRUE; 701 702 switch (classTable->getCharClass(chars[prev]) & CF_CLASS_MASK) { 703 case CC_RESERVED: 704 lastInWord = FALSE; 705 /* fall through */ 706 707 case CC_INDEPENDENT_VOWEL: 708 case CC_ZERO_WIDTH_MARK: 709 for (i = prev; i < syllable; i += 1) { 710 output.writeChar(chars[i], i, tagArray1); 711 } 712 713 break; 714 715 case CC_AL_LAKUNA: 716 case CC_NUKTA: 717 output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1); 718 output.writeChar(chars[prev], prev, tagArray1); 719 break; 720 721 case CC_VIRAMA: 722 // A lone virama is illegal unless it follows a 723 // MALAYALAM_VOWEL_SIGN_U. Such a usage is called 724 // "samvruthokaram". 725 if (chars[prev - 1] != C_MALAYALAM_VOWEL_SIGN_U) { 726 output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1); 727 } 728 729 output.writeChar(chars[prev], prev, tagArray1); 730 break; 731 732 case CC_DEPENDENT_VOWEL: 733 case CC_SPLIT_VOWEL_PIECE_1: 734 case CC_SPLIT_VOWEL_PIECE_2: 735 case CC_SPLIT_VOWEL_PIECE_3: 736 case CC_VOWEL_MODIFIER: 737 case CC_STRESS_MARK: 738 output.writeMpre(); 739 740 output.writeChar(C_DOTTED_CIRCLE, prev, tagArray1); 741 742 output.writeMbelow(); 743 output.writeSMbelow(); 744 output.writeMabove(); 745 746 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) { 747 output.writeMpost(); 748 } 749 750 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) { 751 output.writeVMabove(); 752 output.writeSMabove(); // FIXME: there are no SM's in these scripts... 753 } 754 755 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) { 756 output.writeMpost(); 757 } 758 759 output.writeLengthMark(); 760 output.writeAlLakuna(); 761 762 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) { 763 output.writeVMabove(); 764 output.writeSMabove(); 765 } 766 767 output.writeVMpost(); 768 break; 769 770 case CC_INDEPENDENT_VOWEL_2: 771 case CC_INDEPENDENT_VOWEL_3: 772 case CC_CONSONANT: 773 case CC_CONSONANT_WITH_NUKTA: 774 { 775 le_uint32 length = markStart - prev; 776 le_int32 lastConsonant = markStart - 1; 777 le_int32 baseLimit = prev; 778 779 // Check for REPH at front of syllable 780 if (length > 2 && classTable->isReph(chars[prev]) && classTable->isVirama(chars[prev + 1]) && chars[prev + 2] != C_SIGN_ZWNJ) { 781 baseLimit += 2; 782 783 // Check for eyelash RA, if the script supports it 784 if ((classTable->scriptFlags & SF_EYELASH_RA) != 0 && 785 chars[baseLimit] == C_SIGN_ZWJ) { 786 if (length > 3) { 787 baseLimit += 1; 788 } else { 789 baseLimit -= 2; 790 } 791 } 792 } 793 794 while (lastConsonant > baseLimit && !classTable->isConsonant(chars[lastConsonant])) { 795 lastConsonant -= 1; 796 } 797 798 799 IndicClassTable::CharClass charClass = CC_RESERVED; 800 IndicClassTable::CharClass nextClass = CC_RESERVED; 801 le_int32 baseConsonant = lastConsonant; 802 le_int32 postBase = lastConsonant + 1; 803 le_int32 postBaseLimit = classTable->scriptFlags & SF_POST_BASE_LIMIT_MASK; 804 le_bool seenVattu = FALSE; 805 le_bool seenBelowBaseForm = FALSE; 806 le_bool seenPreBaseForm = FALSE; 807 le_bool hasNukta = FALSE; 808 le_bool hasBelowBaseForm = FALSE; 809 le_bool hasPostBaseForm = FALSE; 810 le_bool hasPreBaseForm = FALSE; 811 812 if (postBase < markStart && classTable->isNukta(chars[postBase])) { 813 charClass = CC_NUKTA; 814 postBase += 1; 815 } 816 817 while (baseConsonant > baseLimit) { 818 nextClass = charClass; 819 hasNukta = IndicClassTable::isNukta(nextClass); 820 charClass = classTable->getCharClass(chars[baseConsonant]); 821 822 hasBelowBaseForm = IndicClassTable::hasBelowBaseForm(charClass) && !hasNukta; 823 hasPostBaseForm = IndicClassTable::hasPostBaseForm(charClass) && !hasNukta; 824 hasPreBaseForm = IndicClassTable::hasPreBaseForm(charClass) && !hasNukta; 825 826 if (IndicClassTable::isConsonant(charClass)) { 827 if (postBaseLimit == 0 || seenVattu || 828 (baseConsonant > baseLimit && !classTable->isVirama(chars[baseConsonant - 1])) || 829 !(hasBelowBaseForm || hasPostBaseForm || hasPreBaseForm)) { 830 break; 831 } 832 833 // Note any pre-base consonants 834 if ( baseConsonant == lastConsonant && lastConsonant > 0 && 835 hasPreBaseForm && classTable->isVirama(chars[baseConsonant - 1])) { 836 output.notePreBaseConsonant(lastConsonant,chars[lastConsonant],chars[lastConsonant-1],tagArray2); 837 seenPreBaseForm = TRUE; 838 839 } 840 // consonants with nuktas are never vattus 841 seenVattu = IndicClassTable::isVattu(charClass) && !hasNukta; 842 843 // consonants with nuktas never have below- or post-base forms 844 if (hasPostBaseForm) { 845 if (seenBelowBaseForm) { 846 break; 847 } 848 849 postBase = baseConsonant; 850 } else if (hasBelowBaseForm) { 851 seenBelowBaseForm = TRUE; 852 } 853 854 postBaseLimit -= 1; 855 } 856 857 baseConsonant -= 1; 858 } 859 860 // Write Mpre 861 output.writeMpre(); 862 863 // Write eyelash RA 864 // NOTE: baseLimit == prev + 3 iff eyelash RA present... 865 if (baseLimit == prev + 3) { 866 output.writeChar(chars[prev], prev, tagArray2); 867 output.writeChar(chars[prev + 1], prev + 1, tagArray2); 868 output.writeChar(chars[prev + 2], prev + 2, tagArray2); 869 } 870 871 // write any pre-base consonants 872 output.writePreBaseConsonant(); 873 874 le_bool supressVattu = TRUE; 875 876 for (i = baseLimit; i < baseConsonant; i += 1) { 877 LEUnicode ch = chars[i]; 878 // Don't put 'pstf' or 'blwf' on anything before the base consonant. 879 FeatureMask features = tagArray1 & ~( pstfFeatureMask | blwfFeatureMask ); 880 881 charClass = classTable->getCharClass(ch); 882 nextClass = classTable->getCharClass(chars[i + 1]); 883 hasNukta = IndicClassTable::isNukta(nextClass); 884 885 if (IndicClassTable::isConsonant(charClass)) { 886 if (IndicClassTable::isVattu(charClass) && !hasNukta && supressVattu) { 887 features = tagArray4; 888 } 889 890 supressVattu = IndicClassTable::isVattu(charClass) && !hasNukta; 891 } else if (IndicClassTable::isVirama(charClass) && chars[i + 1] == C_SIGN_ZWNJ) 892 { 893 features = tagArray4; 894 } 895 896 output.writeChar(ch, i, features); 897 } 898 899 le_int32 bcSpan = baseConsonant + 1; 900 901 if (bcSpan < markStart && classTable->isNukta(chars[bcSpan])) { 902 bcSpan += 1; 903 } 904 905 if (baseConsonant == lastConsonant && bcSpan < markStart && 906 (classTable->isVirama(chars[bcSpan]) || classTable->isAlLakuna(chars[bcSpan]))) { 907 bcSpan += 1; 908 909 if (bcSpan < markStart && chars[bcSpan] == C_SIGN_ZWNJ) { 910 bcSpan += 1; 911 } 912 } 913 914 // note the base consonant for post-GSUB fixups 915 output.noteBaseConsonant(); 916 917 // write base consonant 918 for (i = baseConsonant; i < bcSpan; i += 1) { 919 output.writeChar(chars[i], i, tagArray4); 920 } 921 922 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) != 0) { 923 output.writeMbelow(); 924 output.writeSMbelow(); // FIXME: there are no SMs in these scripts... 925 output.writeMabove(); 926 output.writeMpost(); 927 } 928 929 // write below-base consonants 930 if (baseConsonant != lastConsonant && !seenPreBaseForm) { 931 for (i = bcSpan + 1; i < postBase; i += 1) { 932 output.writeChar(chars[i], i, tagArray1); 933 } 934 935 if (postBase > lastConsonant) { 936 // write halant that was after base consonant 937 output.writeChar(chars[bcSpan], bcSpan, tagArray1); 938 } 939 } 940 941 // write Mbelow, SMbelow, Mabove 942 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) { 943 output.writeMbelow(); 944 output.writeSMbelow(); 945 output.writeMabove(); 946 } 947 948 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) != 0) { 949 if (baseLimit == prev + 2) { 950 output.writeChar(chars[prev], prev, tagArray0); 951 output.writeChar(chars[prev + 1], prev + 1, tagArray0); 952 } 953 954 output.writeVMabove(); 955 output.writeSMabove(); // FIXME: there are no SM's in these scripts... 956 } 957 958 // write post-base consonants 959 // FIXME: does this put the right tags on post-base consonants? 960 if (baseConsonant != lastConsonant && !seenPreBaseForm) { 961 if (postBase <= lastConsonant) { 962 for (i = postBase; i <= lastConsonant; i += 1) { 963 output.writeChar(chars[i], i, tagArray3); 964 } 965 966 // write halant that was after base consonant 967 output.writeChar(chars[bcSpan], bcSpan, tagArray1); 968 } 969 970 // write the training halant, if there is one 971 if (lastConsonant < matra && classTable->isVirama(chars[matra])) { 972 output.writeChar(chars[matra], matra, tagArray4); 973 } 974 } 975 976 // write Mpost 977 if ((classTable->scriptFlags & SF_MATRAS_AFTER_BASE) == 0) { 978 output.writeMpost(); 979 } 980 981 output.writeLengthMark(); 982 output.writeAlLakuna(); 983 984 // write reph 985 if ((classTable->scriptFlags & SF_REPH_AFTER_BELOW) == 0) { 986 if (baseLimit == prev + 2) { 987 output.writeChar(chars[prev], prev, tagArray0); 988 output.writeChar(chars[prev + 1], prev + 1, tagArray0); 989 } 990 991 output.writeVMabove(); 992 output.writeSMabove(); 993 } 994 995 output.writeVMpost(); 996 997 break; 998 } 999 1000 default: 1001 break; 1002 } 1003 1004 prev = syllable; 1005 } 1006 1007 *outMPreFixups = mpreFixups; 1008 1009 return output.getOutputIndex(); 1010 } 1011 1012 void IndicReordering::adjustMPres(MPreFixups *mpreFixups, LEGlyphStorage &glyphStorage, LEErrorCode& success) 1013 { 1014 if (mpreFixups != NULL) { 1015 mpreFixups->apply(glyphStorage, success); 1016 1017 delete mpreFixups; 1018 } 1019 } 1020 1021 void IndicReordering::applyPresentationForms(LEGlyphStorage &glyphStorage, le_int32 count) 1022 { 1023 LEErrorCode success = LE_NO_ERROR; 1024 1025 // This sets us up for 2nd pass of glyph substitution as well as setting the feature masks for the 1026 // GPOS table lookups 1027 1028 for ( le_int32 i = 0 ; i < count ; i++ ) { 1029 glyphStorage.setAuxData(i, ( presentationFormsMask | positioningFormsMask ), success); 1030 } 1031 1032 } 1033 void IndicReordering::finalReordering(LEGlyphStorage &glyphStorage, le_int32 count) 1034 { 1035 LEErrorCode success = LE_NO_ERROR; 1036 1037 // Reposition REPH as appropriate 1038 1039 for ( le_int32 i = 0 ; i < count ; i++ ) { 1040 1041 le_int32 tmpAuxData = glyphStorage.getAuxData(i,success); 1042 LEGlyphID tmpGlyph = glyphStorage.getGlyphID(i,success); 1043 1044 if ( ( tmpGlyph != NO_GLYPH ) && (tmpAuxData & rephConsonantMask) && !(tmpAuxData & repositionedGlyphMask)) { 1045 1046 le_bool targetPositionFound = false; 1047 le_int32 targetPosition = i+1; 1048 le_int32 baseConsonantData; 1049 1050 while (!targetPositionFound) { 1051 tmpGlyph = glyphStorage.getGlyphID(targetPosition,success); 1052 tmpAuxData = glyphStorage.getAuxData(targetPosition,success); 1053 1054 if ( tmpAuxData & baseConsonantMask ) { 1055 baseConsonantData = tmpAuxData; 1056 targetPositionFound = true; 1057 } else { 1058 targetPosition++; 1059 } 1060 } 1061 1062 // Make sure we are not putting the reph into an empty hole 1063 1064 le_bool targetPositionHasGlyph = false; 1065 while (!targetPositionHasGlyph) { 1066 tmpGlyph = glyphStorage.getGlyphID(targetPosition,success); 1067 if ( tmpGlyph != NO_GLYPH ) { 1068 targetPositionHasGlyph = true; 1069 } else { 1070 targetPosition--; 1071 } 1072 } 1073 1074 // Make sure that REPH is positioned after any above base or post base matras 1075 // 1076 le_bool checkMatraDone = false; 1077 le_int32 checkMatraPosition = targetPosition+1; 1078 while ( !checkMatraDone ) { 1079 tmpAuxData = glyphStorage.getAuxData(checkMatraPosition,success); 1080 if ( checkMatraPosition >= count || ( (tmpAuxData ^ baseConsonantData) & LE_GLYPH_GROUP_MASK)) { 1081 checkMatraDone = true; 1082 continue; 1083 } 1084 if ( (tmpAuxData & matraMask) && 1085 (((tmpAuxData & markPositionMask) == aboveBasePosition) || 1086 ((tmpAuxData & markPositionMask) == postBasePosition))) { 1087 targetPosition = checkMatraPosition; 1088 } 1089 checkMatraPosition++; 1090 } 1091 1092 glyphStorage.moveGlyph(i,targetPosition,repositionedGlyphMask); 1093 } 1094 } 1095 } 1096 1097 1098 le_int32 IndicReordering::v2process(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode, 1099 LEUnicode *outChars, LEGlyphStorage &glyphStorage) 1100 { 1101 const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode); 1102 1103 DynamicProperties dynProps[INDIC_BLOCK_SIZE]; 1104 IndicReordering::getDynamicProperties(dynProps,classTable); 1105 1106 IndicReorderingOutput output(outChars, glyphStorage, NULL); 1107 le_int32 i, firstConsonant, baseConsonant, secondConsonant, inv_count = 0, beginSyllable = 0; 1108 //le_bool lastInWord = FALSE; 1109 1110 while (beginSyllable < charCount) { 1111 le_int32 nextSyllable = findSyllable(classTable, chars, beginSyllable, charCount); 1112 1113 output.reset(); 1114 1115 // Find the First Consonant 1116 for ( firstConsonant = beginSyllable ; firstConsonant < nextSyllable ; firstConsonant++ ) { 1117 if ( classTable->isConsonant(chars[firstConsonant]) ) { 1118 break; 1119 } 1120 } 1121 1122 // Find the base consonant 1123 1124 baseConsonant = nextSyllable - 1; 1125 secondConsonant = firstConsonant; 1126 1127 // TODO: Use Dynamic Properties for hasBelowBaseForm and hasPostBaseForm() 1128 1129 while ( baseConsonant > firstConsonant ) { 1130 if ( classTable->isConsonant(chars[baseConsonant]) && 1131 !classTable->hasBelowBaseForm(chars[baseConsonant]) && 1132 !classTable->hasPostBaseForm(chars[baseConsonant]) ) { 1133 break; 1134 } 1135 else { 1136 if ( classTable->isConsonant(chars[baseConsonant]) ) { 1137 secondConsonant = baseConsonant; 1138 } 1139 baseConsonant--; 1140 } 1141 } 1142 1143 // If the syllable starts with Ra + Halant ( in a script that has Reph ) and has more than one 1144 // consonant, Ra is excluced from candidates for base consonants 1145 1146 if ( classTable->isReph(chars[beginSyllable]) && 1147 beginSyllable+1 < nextSyllable && classTable->isVirama(chars[beginSyllable+1]) && 1148 secondConsonant != firstConsonant) { 1149 baseConsonant = secondConsonant; 1150 } 1151 1152 // Populate the output 1153 for ( i = beginSyllable ; i < nextSyllable ; i++ ) { 1154 1155 // Handle invalid combinartions 1156 1157 if ( classTable->isVirama(chars[beginSyllable]) || 1158 classTable->isMatra(chars[beginSyllable]) || 1159 classTable->isVowelModifier(chars[beginSyllable]) || 1160 classTable->isNukta(chars[beginSyllable]) ) { 1161 output.writeChar(C_DOTTED_CIRCLE,beginSyllable,basicShapingFormsMask); 1162 inv_count++; 1163 } 1164 output.writeChar(chars[i],i, basicShapingFormsMask); 1165 1166 } 1167 1168 // Adjust features and set syllable structure bits 1169 1170 for ( i = beginSyllable ; i < nextSyllable ; i++ ) { 1171 1172 FeatureMask outMask = output.getFeatures(i+inv_count); 1173 FeatureMask saveMask = outMask; 1174 1175 // Since reph can only validly occur at the beginning of a syllable 1176 // We only apply it to the first 2 characters in the syllable, to keep it from 1177 // conflicting with other features ( i.e. rkrf ) 1178 1179 // TODO : Use the dynamic property for determining isREPH 1180 if ( i == beginSyllable && i < baseConsonant && classTable->isReph(chars[i]) && 1181 i+1 < nextSyllable && classTable->isVirama(chars[i+1])) { 1182 outMask |= rphfFeatureMask; 1183 outMask |= rephConsonantMask; 1184 output.setFeatures(i+1+inv_count,outMask); 1185 1186 } 1187 1188 if ( i == baseConsonant ) { 1189 outMask |= baseConsonantMask; 1190 } 1191 1192 if ( classTable->isMatra(chars[i])) { 1193 outMask |= matraMask; 1194 if ( classTable->hasAboveBaseForm(chars[i])) { 1195 outMask |= aboveBasePosition; 1196 } else if ( classTable->hasBelowBaseForm(chars[i])) { 1197 outMask |= belowBasePosition; 1198 } 1199 } 1200 1201 // Don't apply half form to virama that stands alone at the end of a syllable 1202 // to prevent half forms from forming when syllable ends with virama 1203 1204 if ( classTable->isVirama(chars[i]) && (i+1 == nextSyllable) ) { 1205 outMask ^= halfFeatureMask; 1206 if ( classTable->isConsonant(chars[i-1]) ) { 1207 FeatureMask tmp = output.getFeatures(i-1+inv_count); 1208 tmp ^= halfFeatureMask; 1209 output.setFeatures(i-1+inv_count,tmp); 1210 } 1211 } 1212 1213 if ( outMask != saveMask ) { 1214 output.setFeatures(i+inv_count,outMask); 1215 } 1216 } 1217 1218 output.decomposeReorderMatras(classTable,beginSyllable,nextSyllable,inv_count); 1219 1220 beginSyllable = nextSyllable; 1221 } 1222 1223 1224 return output.getOutputIndex(); 1225 } 1226 1227 1228 void IndicReordering::getDynamicProperties( DynamicProperties *, const IndicClassTable *classTable ) { 1229 1230 1231 LEUnicode currentChar; 1232 LEUnicode workChars[2]; 1233 LEGlyphStorage workGlyphs; 1234 1235 IndicReorderingOutput workOutput(workChars, workGlyphs, NULL); 1236 1237 //le_int32 offset = 0; 1238 1239 #if 0 1240 // TODO: Should this section of code have actually been doing something? 1241 // First find the relevant virama for the script we are dealing with 1242 LEUnicode virama; 1243 for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) { 1244 if ( classTable->isVirama(currentChar)) { 1245 virama = currentChar; 1246 break; 1247 } 1248 } 1249 #endif 1250 1251 for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) { 1252 if ( classTable->isConsonant(currentChar)) { 1253 workOutput.reset(); 1254 } 1255 } 1256 1257 1258 } 1259 1260 U_NAMESPACE_END