+void IndicReordering::applyPresentationForms(LEGlyphStorage &glyphStorage, le_int32 count)
+{
+ LEErrorCode success = LE_NO_ERROR;
+
+// This sets us up for 2nd pass of glyph substitution as well as setting the feature masks for the
+// GPOS table lookups
+
+ for ( le_int32 i = 0 ; i < count ; i++ ) {
+ glyphStorage.setAuxData(i, ( presentationFormsMask | positioningFormsMask ), success);
+ }
+
+}
+void IndicReordering::finalReordering(LEGlyphStorage &glyphStorage, le_int32 count)
+{
+ LEErrorCode success = LE_NO_ERROR;
+
+ // Reposition REPH as appropriate
+
+ for ( le_int32 i = 0 ; i < count ; i++ ) {
+
+ le_int32 tmpAuxData = glyphStorage.getAuxData(i,success);
+ LEGlyphID tmpGlyph = glyphStorage.getGlyphID(i,success);
+
+ if ( ( tmpGlyph != NO_GLYPH ) && (tmpAuxData & rephConsonantMask) && !(tmpAuxData & repositionedGlyphMask)) {
+
+ le_bool targetPositionFound = false;
+ le_int32 targetPosition = i+1;
+ le_int32 baseConsonantData;
+
+ while (!targetPositionFound) {
+ tmpGlyph = glyphStorage.getGlyphID(targetPosition,success);
+ tmpAuxData = glyphStorage.getAuxData(targetPosition,success);
+
+ if ( tmpAuxData & baseConsonantMask ) {
+ baseConsonantData = tmpAuxData;
+ targetPositionFound = true;
+ } else {
+ targetPosition++;
+ }
+ }
+
+ // Make sure we are not putting the reph into an empty hole
+
+ le_bool targetPositionHasGlyph = false;
+ while (!targetPositionHasGlyph) {
+ tmpGlyph = glyphStorage.getGlyphID(targetPosition,success);
+ if ( tmpGlyph != NO_GLYPH ) {
+ targetPositionHasGlyph = true;
+ } else {
+ targetPosition--;
+ }
+ }
+
+ // Make sure that REPH is positioned after any above base or post base matras
+ //
+ le_bool checkMatraDone = false;
+ le_int32 checkMatraPosition = targetPosition+1;
+ while ( !checkMatraDone ) {
+ tmpAuxData = glyphStorage.getAuxData(checkMatraPosition,success);
+ if ( checkMatraPosition >= count || ( (tmpAuxData ^ baseConsonantData) & LE_GLYPH_GROUP_MASK)) {
+ checkMatraDone = true;
+ continue;
+ }
+ if ( (tmpAuxData & matraMask) &&
+ (((tmpAuxData & markPositionMask) == aboveBasePosition) ||
+ ((tmpAuxData & markPositionMask) == postBasePosition))) {
+ targetPosition = checkMatraPosition;
+ }
+ checkMatraPosition++;
+ }
+
+ glyphStorage.moveGlyph(i,targetPosition,repositionedGlyphMask);
+ }
+ }
+}
+
+
+le_int32 IndicReordering::v2process(const LEUnicode *chars, le_int32 charCount, le_int32 scriptCode,
+ LEUnicode *outChars, LEGlyphStorage &glyphStorage)
+{
+ const IndicClassTable *classTable = IndicClassTable::getScriptClassTable(scriptCode);
+ if (classTable == NULL) {
+ return 0;
+ }
+
+ DynamicProperties dynProps[INDIC_BLOCK_SIZE];
+ IndicReordering::getDynamicProperties(dynProps,classTable);
+
+ IndicReorderingOutput output(outChars, glyphStorage, NULL);
+ le_int32 i, firstConsonant, baseConsonant, secondConsonant, inv_count = 0, beginSyllable = 0;
+ //le_bool lastInWord = FALSE;
+
+ while (beginSyllable < charCount) {
+ le_int32 nextSyllable = findSyllable(classTable, chars, beginSyllable, charCount);
+
+ output.reset();
+
+ // Find the First Consonant
+ for ( firstConsonant = beginSyllable ; firstConsonant < nextSyllable ; firstConsonant++ ) {
+ if ( classTable->isConsonant(chars[firstConsonant]) ) {
+ break;
+ }
+ }
+
+ // Find the base consonant
+
+ baseConsonant = nextSyllable - 1;
+ secondConsonant = firstConsonant;
+
+ // TODO: Use Dynamic Properties for hasBelowBaseForm and hasPostBaseForm()
+
+ while ( baseConsonant > firstConsonant ) {
+ if ( classTable->isConsonant(chars[baseConsonant]) &&
+ !classTable->hasBelowBaseForm(chars[baseConsonant]) &&
+ !classTable->hasPostBaseForm(chars[baseConsonant]) ) {
+ break;
+ }
+ else {
+ if ( classTable->isConsonant(chars[baseConsonant]) ) {
+ secondConsonant = baseConsonant;
+ }
+ baseConsonant--;
+ }
+ }
+
+ // If the syllable starts with Ra + Halant ( in a script that has Reph ) and has more than one
+ // consonant, Ra is excluced from candidates for base consonants
+
+ if ( classTable->isReph(chars[beginSyllable]) &&
+ beginSyllable+1 < nextSyllable && classTable->isVirama(chars[beginSyllable+1]) &&
+ secondConsonant != firstConsonant) {
+ baseConsonant = secondConsonant;
+ }
+
+ // Populate the output
+ for ( i = beginSyllable ; i < nextSyllable ; i++ ) {
+
+ // Handle invalid combinartions
+
+ if ( classTable->isVirama(chars[beginSyllable]) ||
+ classTable->isMatra(chars[beginSyllable]) ||
+ classTable->isVowelModifier(chars[beginSyllable]) ||
+ classTable->isNukta(chars[beginSyllable]) ) {
+ output.writeChar(C_DOTTED_CIRCLE,beginSyllable,basicShapingFormsMask);
+ inv_count++;
+ }
+ output.writeChar(chars[i],i, basicShapingFormsMask);
+
+ }
+
+ // Adjust features and set syllable structure bits
+
+ for ( i = beginSyllable ; i < nextSyllable ; i++ ) {
+
+ FeatureMask outMask = output.getFeatures(i+inv_count);
+ FeatureMask saveMask = outMask;
+
+ // Since reph can only validly occur at the beginning of a syllable
+ // We only apply it to the first 2 characters in the syllable, to keep it from
+ // conflicting with other features ( i.e. rkrf )
+
+ // TODO : Use the dynamic property for determining isREPH
+ if ( i == beginSyllable && i < baseConsonant && classTable->isReph(chars[i]) &&
+ i+1 < nextSyllable && classTable->isVirama(chars[i+1])) {
+ outMask |= rphfFeatureMask;
+ outMask |= rephConsonantMask;
+ output.setFeatures(i+1+inv_count,outMask);
+
+ }
+
+ if ( i == baseConsonant ) {
+ outMask |= baseConsonantMask;
+ }
+
+ if ( classTable->isMatra(chars[i])) {
+ outMask |= matraMask;
+ if ( classTable->hasAboveBaseForm(chars[i])) {
+ outMask |= aboveBasePosition;
+ } else if ( classTable->hasBelowBaseForm(chars[i])) {
+ outMask |= belowBasePosition;
+ }
+ }
+
+ // Don't apply half form to virama that stands alone at the end of a syllable
+ // to prevent half forms from forming when syllable ends with virama
+
+ if ( classTable->isVirama(chars[i]) && (i+1 == nextSyllable) ) {
+ outMask ^= halfFeatureMask;
+ if ( classTable->isConsonant(chars[i-1]) ) {
+ FeatureMask tmp = output.getFeatures(i-1+inv_count);
+ tmp ^= halfFeatureMask;
+ output.setFeatures(i-1+inv_count,tmp);
+ }
+ }
+
+ if ( outMask != saveMask ) {
+ output.setFeatures(i+inv_count,outMask);
+ }
+ }
+
+ output.decomposeReorderMatras(classTable,beginSyllable,nextSyllable,inv_count);
+
+ beginSyllable = nextSyllable;
+ }
+
+
+ return output.getOutputIndex();
+}
+
+
+void IndicReordering::getDynamicProperties( DynamicProperties *, const IndicClassTable *classTable ) {
+
+
+ LEUnicode currentChar;
+ LEUnicode workChars[2];
+ LEGlyphStorage workGlyphs;
+
+ IndicReorderingOutput workOutput(workChars, workGlyphs, NULL);
+
+ //le_int32 offset = 0;
+
+#if 0
+// TODO: Should this section of code have actually been doing something?
+ // First find the relevant virama for the script we are dealing with
+ LEUnicode virama;
+ for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) {
+ if ( classTable->isVirama(currentChar)) {
+ virama = currentChar;
+ break;
+ }
+ }
+#endif
+
+ for ( currentChar = classTable->firstChar ; currentChar <= classTable->lastChar ; currentChar++ ) {
+ if ( classTable->isConsonant(currentChar)) {
+ workOutput.reset();
+ }
+ }
+
+
+}
+