Home | History | Annotate | Download | only in layout
      1 
      2 /*
      3  *
      4  * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved
      5  *
      6  */
      7 
      8 #include "LETypes.h"
      9 #include "LEScripts.h"
     10 #include "LELanguages.h"
     11 
     12 #include "LayoutEngine.h"
     13 #include "CanonShaping.h"
     14 #include "OpenTypeLayoutEngine.h"
     15 #include "ScriptAndLanguageTags.h"
     16 #include "CharSubstitutionFilter.h"
     17 
     18 #include "GlyphSubstitutionTables.h"
     19 #include "GlyphDefinitionTables.h"
     20 #include "GlyphPositioningTables.h"
     21 
     22 #include "LEGlyphStorage.h"
     23 #include "GlyphPositionAdjustments.h"
     24 
     25 #include "GDEFMarkFilter.h"
     26 
     27 #include "KernTable.h"
     28 
     29 U_NAMESPACE_BEGIN
     30 
     31 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine)
     32 
     33 #define ccmpFeatureTag LE_CCMP_FEATURE_TAG
     34 #define ligaFeatureTag LE_LIGA_FEATURE_TAG
     35 #define cligFeatureTag LE_CLIG_FEATURE_TAG
     36 #define kernFeatureTag LE_KERN_FEATURE_TAG
     37 #define markFeatureTag LE_MARK_FEATURE_TAG
     38 #define mkmkFeatureTag LE_MKMK_FEATURE_TAG
     39 #define loclFeatureTag LE_LOCL_FEATURE_TAG
     40 #define caltFeatureTag LE_CALT_FEATURE_TAG
     41 
     42 #define dligFeatureTag LE_DLIG_FEATURE_TAG
     43 #define rligFeatureTag LE_RLIG_FEATURE_TAG
     44 #define paltFeatureTag LE_PALT_FEATURE_TAG
     45 
     46 #define hligFeatureTag LE_HLIG_FEATURE_TAG
     47 #define smcpFeatureTag LE_SMCP_FEATURE_TAG
     48 #define fracFeatureTag LE_FRAC_FEATURE_TAG
     49 #define afrcFeatureTag LE_AFRC_FEATURE_TAG
     50 #define zeroFeatureTag LE_ZERO_FEATURE_TAG
     51 #define swshFeatureTag LE_SWSH_FEATURE_TAG
     52 #define cswhFeatureTag LE_CSWH_FEATURE_TAG
     53 #define saltFeatureTag LE_SALT_FEATURE_TAG
     54 #define naltFeatureTag LE_NALT_FEATURE_TAG
     55 #define rubyFeatureTag LE_RUBY_FEATURE_TAG
     56 #define ss01FeatureTag LE_SS01_FEATURE_TAG
     57 #define ss02FeatureTag LE_SS02_FEATURE_TAG
     58 #define ss03FeatureTag LE_SS03_FEATURE_TAG
     59 #define ss04FeatureTag LE_SS04_FEATURE_TAG
     60 #define ss05FeatureTag LE_SS05_FEATURE_TAG
     61 #define ss06FeatureTag LE_SS06_FEATURE_TAG
     62 #define ss07FeatureTag LE_SS07_FEATURE_TAG
     63 
     64 #define ccmpFeatureMask 0x80000000UL
     65 #define ligaFeatureMask 0x40000000UL
     66 #define cligFeatureMask 0x20000000UL
     67 #define kernFeatureMask 0x10000000UL
     68 #define paltFeatureMask 0x08000000UL
     69 #define markFeatureMask 0x04000000UL
     70 #define mkmkFeatureMask 0x02000000UL
     71 #define loclFeatureMask 0x01000000UL
     72 #define caltFeatureMask 0x00800000UL
     73 
     74 #define dligFeatureMask 0x00400000UL
     75 #define rligFeatureMask 0x00200000UL
     76 #define hligFeatureMask 0x00100000UL
     77 #define smcpFeatureMask 0x00080000UL
     78 #define fracFeatureMask 0x00040000UL
     79 #define afrcFeatureMask 0x00020000UL
     80 #define zeroFeatureMask 0x00010000UL
     81 #define swshFeatureMask 0x00008000UL
     82 #define cswhFeatureMask 0x00004000UL
     83 #define saltFeatureMask 0x00002000UL
     84 #define naltFeatureMask 0x00001000UL
     85 #define rubyFeatureMask 0x00000800UL
     86 #define ss01FeatureMask 0x00000400UL
     87 #define ss02FeatureMask 0x00000200UL
     88 #define ss03FeatureMask 0x00000100UL
     89 #define ss04FeatureMask 0x00000080UL
     90 #define ss05FeatureMask 0x00000040UL
     91 #define ss06FeatureMask 0x00000020UL
     92 #define ss07FeatureMask 0x00000010UL
     93 
     94 #define minimalFeatures     (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask)
     95 
     96 static const FeatureMap featureMap[] =
     97 {
     98     {ccmpFeatureTag, ccmpFeatureMask},
     99     {ligaFeatureTag, ligaFeatureMask},
    100     {cligFeatureTag, cligFeatureMask},
    101     {kernFeatureTag, kernFeatureMask},
    102     {paltFeatureTag, paltFeatureMask},
    103     {markFeatureTag, markFeatureMask},
    104     {mkmkFeatureTag, mkmkFeatureMask},
    105     {loclFeatureTag, loclFeatureMask},
    106     {caltFeatureTag, caltFeatureMask},
    107     {hligFeatureTag, hligFeatureMask},
    108     {smcpFeatureTag, smcpFeatureMask},
    109     {fracFeatureTag, fracFeatureMask},
    110     {afrcFeatureTag, afrcFeatureMask},
    111     {zeroFeatureTag, zeroFeatureMask},
    112     {swshFeatureTag, swshFeatureMask},
    113     {cswhFeatureTag, cswhFeatureMask},
    114     {saltFeatureTag, saltFeatureMask},
    115     {naltFeatureTag, naltFeatureMask},
    116     {rubyFeatureTag, rubyFeatureMask},
    117     {ss01FeatureTag, ss01FeatureMask},
    118     {ss02FeatureTag, ss02FeatureMask},
    119     {ss03FeatureTag, ss03FeatureMask},
    120     {ss04FeatureTag, ss04FeatureMask},
    121     {ss05FeatureTag, ss05FeatureMask},
    122     {ss06FeatureTag, ss06FeatureMask},
    123     {ss07FeatureTag, ss07FeatureMask}
    124 };
    125 
    126 static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);
    127 
    128 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
    129                         le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
    130     : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures),
    131       fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE),
    132       fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
    133 {
    134     static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG;
    135     static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG;
    136     const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag);
    137 
    138     switch (typoFlags & (LE_SS01_FEATURE_FLAG
    139                          | LE_SS02_FEATURE_FLAG
    140                          | LE_SS03_FEATURE_FLAG
    141                          | LE_SS04_FEATURE_FLAG
    142                          | LE_SS05_FEATURE_FLAG
    143                          | LE_SS06_FEATURE_FLAG
    144                          | LE_SS07_FEATURE_FLAG)) {
    145         case LE_SS01_FEATURE_FLAG:
    146             fFeatureMask |= ss01FeatureMask;
    147             break;
    148         case LE_SS02_FEATURE_FLAG:
    149             fFeatureMask |= ss02FeatureMask;
    150             break;
    151         case LE_SS03_FEATURE_FLAG:
    152             fFeatureMask |= ss03FeatureMask;
    153             break;
    154         case LE_SS04_FEATURE_FLAG:
    155             fFeatureMask |= ss04FeatureMask;
    156             break;
    157         case LE_SS05_FEATURE_FLAG:
    158             fFeatureMask |= ss05FeatureMask;
    159             break;
    160         case LE_SS06_FEATURE_FLAG:
    161             fFeatureMask |= ss06FeatureMask;
    162             break;
    163         case LE_SS07_FEATURE_FLAG:
    164             fFeatureMask |= ss07FeatureMask;
    165             break;
    166     }
    167 
    168     if (typoFlags & LE_Kerning_FEATURE_FLAG) {
    169       fFeatureMask |= (kernFeatureMask | paltFeatureMask);
    170       // Convenience.
    171     }
    172     if (typoFlags & LE_Ligatures_FEATURE_FLAG) {
    173       fFeatureMask |= (ligaFeatureMask | cligFeatureMask);
    174       // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ?
    175     }
    176     if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask;
    177     if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask;
    178     if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask;
    179     if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask;
    180     if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask;
    181     if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask;
    182     if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask;
    183     if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask;
    184     if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask;
    185     if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask;
    186     if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask;
    187     if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask;
    188     if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask;
    189     if (typoFlags & LE_NALT_FEATURE_FLAG) {
    190       // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm
    191       fFeatureMask = naltFeatureMask;
    192     }
    193 
    194     if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) {
    195       // This isn't a font feature, but requests a Char Substitution Filter
    196       fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
    197     }
    198 
    199     setScriptAndLanguageTags();
    200 
    201     fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag);
    202 
    203 // JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font
    204 //    if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) {
    205     if (gposTable != NULL && gposTable->coversScript(fScriptTag)) {
    206         fGPOSTable = gposTable;
    207     }
    208 }
    209 
    210 void OpenTypeLayoutEngine::reset()
    211 {
    212     // NOTE: if we're called from
    213     // the destructor, LayoutEngine;:reset()
    214     // will have been called already by
    215     // LayoutEngine::~LayoutEngine()
    216     LayoutEngine::reset();
    217 }
    218 
    219 OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
    220                        le_int32 typoFlags, LEErrorCode &success)
    221     : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE),
    222       fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL)
    223 {
    224     setScriptAndLanguageTags();
    225 }
    226 
    227 OpenTypeLayoutEngine::~OpenTypeLayoutEngine()
    228 {
    229     if (fTypoFlags & 0x80000000L) {
    230         delete fSubstitutionFilter;
    231     }
    232 
    233     reset();
    234 }
    235 
    236 LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode)
    237 {
    238     if (scriptCode < 0 || scriptCode >= scriptCodeCount) {
    239         return 0xFFFFFFFF;
    240     }
    241     return scriptTags[scriptCode];
    242 }
    243 
    244 LETag OpenTypeLayoutEngine::getV2ScriptTag(le_int32 scriptCode)
    245 {
    246 	switch (scriptCode) {
    247 		case bengScriptCode :    return bng2ScriptTag;
    248 		case devaScriptCode :    return dev2ScriptTag;
    249 		case gujrScriptCode :    return gjr2ScriptTag;
    250 		case guruScriptCode :    return gur2ScriptTag;
    251 		case kndaScriptCode :    return knd2ScriptTag;
    252 		case mlymScriptCode :    return mlm2ScriptTag;
    253 		case oryaScriptCode :    return ory2ScriptTag;
    254 		case tamlScriptCode :    return tml2ScriptTag;
    255 		case teluScriptCode :    return tel2ScriptTag;
    256 		default:                 return nullScriptTag;
    257 	}
    258 }
    259 
    260 LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode)
    261 {
    262     if (languageCode < 0 || languageCode >= languageCodeCount) {
    263         return 0xFFFFFFFF;
    264     }
    265 
    266     return languageTags[languageCode];
    267 }
    268 
    269 void OpenTypeLayoutEngine::setScriptAndLanguageTags()
    270 {
    271     fScriptTag  = getScriptTag(fScriptCode);
    272     fScriptTagV2 = getV2ScriptTag(fScriptCode);
    273     fLangSysTag = getLangSysTag(fLanguageCode);
    274 }
    275 
    276 le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
    277                 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
    278 {
    279     if (LE_FAILURE(success)) {
    280         return 0;
    281     }
    282 
    283     if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
    284         success = LE_ILLEGAL_ARGUMENT_ERROR;
    285         return 0;
    286     }
    287 
    288     // This is the cheapest way to get mark reordering only for Hebrew.
    289     // We could just do the mark reordering for all scripts, but most
    290     // of them probably don't need it... Another option would be to
    291     // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it
    292     // would need to do is mark reordering, so that seems like overkill.
    293     if (fScriptCode == hebrScriptCode) {
    294         outChars = LE_NEW_ARRAY(LEUnicode, count);
    295 
    296         if (outChars == NULL) {
    297             success = LE_MEMORY_ALLOCATION_ERROR;
    298             return 0;
    299         }
    300 
    301         if (LE_FAILURE(success)) {
    302             LE_DELETE_ARRAY(outChars);
    303             return 0;
    304         }
    305 
    306         CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage);
    307     }
    308 
    309     if (LE_FAILURE(success)) {
    310         return 0;
    311     }
    312 
    313     glyphStorage.allocateGlyphArray(count, rightToLeft, success);
    314     glyphStorage.allocateAuxData(success);
    315 
    316     for (le_int32 i = 0; i < count; i += 1) {
    317         glyphStorage.setAuxData(i, fFeatureMask, success);
    318     }
    319 
    320     return count;
    321 }
    322 
    323 // Input: characters, tags
    324 // Output: glyphs, char indices
    325 le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
    326                                                LEGlyphStorage &glyphStorage, LEErrorCode &success)
    327 {
    328     if (LE_FAILURE(success)) {
    329         return 0;
    330     }
    331 
    332     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
    333         success = LE_ILLEGAL_ARGUMENT_ERROR;
    334         return 0;
    335     }
    336 
    337     mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
    338 
    339     if (LE_FAILURE(success)) {
    340         return 0;
    341     }
    342 
    343     if (fGSUBTable != NULL) {
    344         if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) {
    345             count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter,
    346                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
    347 
    348         } else {
    349         count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
    350                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
    351         }
    352     }
    353 
    354     return count;
    355 }
    356 // Input: characters, tags
    357 // Output: glyphs, char indices
    358 le_int32 OpenTypeLayoutEngine::glyphSubstitution(le_int32 count, le_int32 max, le_bool rightToLeft,
    359                                                LEGlyphStorage &glyphStorage, LEErrorCode &success)
    360 {
    361     if (LE_FAILURE(success)) {
    362         return 0;
    363     }
    364 
    365     if ( count < 0 || max < 0 ) {
    366         success = LE_ILLEGAL_ARGUMENT_ERROR;
    367         return 0;
    368     }
    369 
    370     if (fGSUBTable != NULL) {
    371         if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) {
    372             count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter,
    373                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
    374 
    375         } else {
    376         count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter,
    377                                     fFeatureMap, fFeatureMapCount, fFeatureOrder, success);
    378         }
    379     }
    380 
    381     return count;
    382 }
    383 le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
    384 {
    385     if (LE_FAILURE(success)) {
    386         return 0;
    387     }
    388 
    389     glyphStorage.adoptGlyphArray(tempGlyphStorage);
    390     glyphStorage.adoptCharIndicesArray(tempGlyphStorage);
    391     glyphStorage.adoptAuxDataArray(tempGlyphStorage);
    392     glyphStorage.adoptGlyphCount(tempGlyphStorage);
    393 
    394     return glyphStorage.getGlyphCount();
    395 }
    396 
    397 le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEGlyphStorage &glyphStorage, LEErrorCode &success)
    398 {
    399     LEUnicode *outChars = NULL;
    400     LEGlyphStorage fakeGlyphStorage;
    401     le_int32 outCharCount, outGlyphCount;
    402 
    403     if (LE_FAILURE(success)) {
    404         return 0;
    405     }
    406 
    407     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
    408         success = LE_ILLEGAL_ARGUMENT_ERROR;
    409         return 0;
    410     }
    411 
    412     outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, fakeGlyphStorage, success);
    413 
    414     if (LE_FAILURE(success)) {
    415         return 0;
    416     }
    417 
    418     if (outChars != NULL) {
    419         // le_int32 fakeGlyphCount =
    420         glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success);
    421         LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
    422         //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount);
    423     } else {
    424         // le_int32 fakeGlyphCount =
    425         glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success);
    426         //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount);
    427     }
    428 
    429     if (LE_FAILURE(success)) {
    430         return 0;
    431     }
    432 
    433     outGlyphCount = glyphPostProcessing(fakeGlyphStorage, glyphStorage, success);
    434 
    435     return outGlyphCount;
    436 }
    437 
    438 // apply GPOS table, if any
    439 void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse,
    440                                                 LEGlyphStorage &glyphStorage, LEErrorCode &success)
    441 {
    442     if (LE_FAILURE(success)) {
    443         return;
    444     }
    445 
    446     if (chars == NULL || offset < 0 || count < 0) {
    447         success = LE_ILLEGAL_ARGUMENT_ERROR;
    448         return;
    449     }
    450 
    451     le_int32 glyphCount = glyphStorage.getGlyphCount();
    452     if (glyphCount == 0) {
    453         return;
    454     }
    455 
    456     if (fGPOSTable != NULL) {
    457         GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount);
    458         le_int32 i;
    459 
    460         if (adjustments == NULL) {
    461             success = LE_MEMORY_ALLOCATION_ERROR;
    462             return;
    463         }
    464 
    465 #if 0
    466         // Don't need to do this if we allocate
    467         // the adjustments array w/ new...
    468         for (i = 0; i < glyphCount; i += 1) {
    469             adjustments->setXPlacement(i, 0);
    470             adjustments->setYPlacement(i, 0);
    471 
    472             adjustments->setXAdvance(i, 0);
    473             adjustments->setYAdvance(i, 0);
    474 
    475             adjustments->setBaseOffset(i, -1);
    476         }
    477 #endif
    478 
    479         if (fGPOSTable != NULL) {
    480             if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) {
    481                 fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance,
    482                                 fFeatureMap, fFeatureMapCount, fFeatureOrder);
    483 
    484             } else {
    485                 fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance,
    486                                 fFeatureMap, fFeatureMapCount, fFeatureOrder);
    487             }
    488         } else if ( fTypoFlags & 0x1 ) {
    489             static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
    490             KernTable kt(fFontInstance, getFontTable(kernTableTag));
    491             kt.process(glyphStorage);
    492         }
    493 
    494         float xAdjust = 0, yAdjust = 0;
    495 
    496         for (i = 0; i < glyphCount; i += 1) {
    497             float xAdvance   = adjustments->getXAdvance(i);
    498             float yAdvance   = adjustments->getYAdvance(i);
    499             float xPlacement = 0;
    500             float yPlacement = 0;
    501 
    502 
    503 #if 0
    504             // This is where separate kerning adjustments
    505             // should get applied.
    506             xAdjust += xKerning;
    507             yAdjust += yKerning;
    508 #endif
    509 
    510             for (le_int32 base = i; base >= 0; base = adjustments->getBaseOffset(base)) {
    511                 xPlacement += adjustments->getXPlacement(base);
    512                 yPlacement += adjustments->getYPlacement(base);
    513             }
    514 
    515             xPlacement = fFontInstance->xUnitsToPoints(xPlacement);
    516             yPlacement = fFontInstance->yUnitsToPoints(yPlacement);
    517             glyphStorage.adjustPosition(i, xAdjust + xPlacement, -(yAdjust + yPlacement), success);
    518 
    519             xAdjust += fFontInstance->xUnitsToPoints(xAdvance);
    520             yAdjust += fFontInstance->yUnitsToPoints(yAdvance);
    521         }
    522 
    523         glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success);
    524 
    525         delete adjustments;
    526     } else {
    527         // if there was no GPOS table, maybe there's non-OpenType kerning we can use
    528         //   Google Patch: disable this.  Causes problems with Tamil.
    529         //       Umesh says layout is poor both with and without the change, but
    530         //       worse with the change.  See ocean/imageprocessing/layout_test_unittest.cc
    531         //   Public ICU ticket for this problem is  #7742
    532         // LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
    533     }
    534 
    535     LEGlyphID zwnj  = fFontInstance->mapCharToGlyph(0x200C);
    536 
    537     if (zwnj != 0x0000) {
    538         for (le_int32 g = 0; g < glyphCount; g += 1) {
    539             LEGlyphID glyph = glyphStorage[g];
    540 
    541             if (glyph == zwnj) {
    542                 glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF);
    543             }
    544         }
    545     }
    546 
    547 #if 0
    548     // Don't know why this is here...
    549     LE_DELETE_ARRAY(fFeatureTags);
    550     fFeatureTags = NULL;
    551 #endif
    552 }
    553 
    554 U_NAMESPACE_END
    555