os/textandloc/fontservices/textshaperplugin/IcuSource/layout/LayoutEngine.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 
     2 /*
     3  *
     4  * (C) Copyright IBM Corp. 1998-2005 - 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 "ArabicLayoutEngine.h"
    14 #include "CanonShaping.h"
    15 #include "HanLayoutEngine.h"
    16 #include "IndicLayoutEngine.h"
    17 #include "KhmerLayoutEngine.h"
    18 #include "ThaiLayoutEngine.h"
    19 #include "GXLayoutEngine.h"
    20 #include "ScriptAndLanguageTags.h"
    21 #include "CharSubstitutionFilter.h"
    22 
    23 #include "LEGlyphStorage.h"
    24 
    25 #include "OpenTypeUtilities.h"
    26 #include "GlyphSubstitutionTables.h"
    27 #include "MorphTables.h"
    28 
    29 #include "DefaultCharMapper.h"
    30 
    31 #include "KernTable.h"
    32 
    33 U_NAMESPACE_BEGIN
    34 
    35 #define ARRAY_SIZE(array) (sizeof array  / sizeof array[0])
    36 
    37 const LEUnicode32 DefaultCharMapper::controlChars[] = {
    38     0x0009, 0x000A, 0x000D,
    39     /*0x200C, 0x200D,*/ 0x200E, 0x200F,
    40     0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E,
    41     0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F
    42 };
    43 
    44 const le_int32 DefaultCharMapper::controlCharsCount = ARRAY_SIZE(controlChars);
    45 
    46 const LEUnicode32 DefaultCharMapper::mirroredChars[] = {
    47     0x0028, 0x0029, // ascii paired punctuation
    48     0x003c, 0x003e,
    49     0x005b, 0x005d,
    50     0x007b, 0x007d,
    51     0x2045, 0x2046, // math symbols (not complete)
    52     0x207d, 0x207e,
    53     0x208d, 0x208e,
    54     0x2264, 0x2265,
    55     0x3008, 0x3009, // chinese paired punctuation
    56     0x300a, 0x300b,
    57     0x300c, 0x300d,
    58     0x300e, 0x300f,
    59     0x3010, 0x3011,
    60     0x3014, 0x3015,
    61     0x3016, 0x3017,
    62     0x3018, 0x3019,
    63     0x301a, 0x301b
    64 };
    65 
    66 const le_int32 DefaultCharMapper::mirroredCharsCount = ARRAY_SIZE(mirroredChars);
    67 
    68 LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) const
    69 {
    70     if (fFilterControls) {
    71         le_int32 index = OpenTypeUtilities::search((le_uint32)ch, (le_uint32 *)controlChars, controlCharsCount);
    72 
    73         if (controlChars[index] == ch) {
    74             return 0xFFFF;
    75         }
    76     }
    77 
    78     if (fMirror) {
    79         le_int32 index = OpenTypeUtilities::search((le_uint32) ch, (le_uint32 *)mirroredChars, mirroredCharsCount);
    80 
    81         if (mirroredChars[index] == ch) {
    82             le_int32 mirrorOffset = ((index & 1) == 0) ? 1 : -1;
    83 
    84             return mirroredChars[index + mirrorOffset];
    85         }
    86     }
    87 
    88     return ch;
    89 }
    90 
    91 // This is here to get it out of LEGlyphFilter.h.
    92 // No particular reason to put it here, other than
    93 // this is a good central location...
    94 LEGlyphFilter::~LEGlyphFilter()
    95 {
    96     // nothing to do
    97 }
    98 
    99 CharSubstitutionFilter::CharSubstitutionFilter(const LEFontInstance *fontInstance)
   100   : fFontInstance(fontInstance)
   101 {
   102     // nothing to do
   103 }
   104 
   105 CharSubstitutionFilter::~CharSubstitutionFilter()
   106 {
   107     // nothing to do
   108 }
   109 
   110 
   111 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine)
   112 
   113 static const LETag emptyTag = 0x00000000;
   114 
   115 static const LETag ccmpFeatureTag = LE_CCMP_FEATURE_TAG;
   116 
   117 static const LETag canonFeatures[] = {ccmpFeatureTag, emptyTag};
   118 
   119 LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags)
   120   : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode),
   121     fTypoFlags(typoFlags), fGidOfRA(0)
   122 {
   123     fGlyphStorage = new LEGlyphStorage();
   124 }
   125 
   126 le_bool LayoutEngine::isBogus()
   127 {
   128     return fGlyphStorage? FALSE : TRUE;
   129 }
   130 
   131 le_int32 LayoutEngine::getGlyphCount() const
   132 {
   133     return fGlyphStorage->getGlyphCount();
   134 }
   135 
   136 void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase, LEErrorCode &success) const
   137 {
   138     fGlyphStorage->getCharIndices(charIndices, indexBase, success);
   139 }
   140 
   141 void LayoutEngine::getCharIndices(le_int32 charIndices[], LEErrorCode &success) const
   142 {
   143     fGlyphStorage->getCharIndices(charIndices, success);
   144 }
   145 
   146 // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits
   147 void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits, LEErrorCode &success) const
   148 {
   149     fGlyphStorage->getGlyphs(glyphs, extraBits, success);
   150 }
   151 
   152 void LayoutEngine::getGlyphs(LEGlyphID glyphs[], LEErrorCode &success) const
   153 {
   154     fGlyphStorage->getGlyphs(glyphs, success);
   155 }
   156 
   157 
   158 void LayoutEngine::getGlyphPositions(float positions[], LEErrorCode &success) const
   159 {
   160     fGlyphStorage->getGlyphPositions(positions, success);
   161 }
   162 
   163 void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEErrorCode &success) const
   164 {
   165     fGlyphStorage->getGlyphPosition(glyphIndex, x, y, success);
   166 }
   167 
   168 le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
   169                 LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
   170 {
   171     if (LE_FAILURE(success)) {
   172         return 0;
   173     }
   174 
   175     if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
   176         success = LE_ILLEGAL_ARGUMENT_ERROR;
   177         return 0;
   178     }
   179 
   180     const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
   181     LETag scriptTag  = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
   182     LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
   183     le_int32 i, dir = 1, out = 0, outCharCount = count;
   184 
   185     if (canonGSUBTable->coversScript(scriptTag)) {
   186         CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance);
   187         if (!substitutionFilter) {
   188             success = LE_MEMORY_ALLOCATION_ERROR;
   189             return 0;
   190         }
   191 
   192 		const LEUnicode *inChars = &chars[offset];
   193 		LEUnicode *reordered = NULL;
   194 
   195 		// This is the cheapest way to get mark reordering only for Hebrew.
   196 		// We could just do the mark reordering for all scripts, but most
   197 		// of them probably don't need it...
   198 		if (fScriptCode == hebrScriptCode) {
   199 			reordered = LE_NEW_ARRAY(LEUnicode, count);
   200 
   201 			if (reordered == NULL) {
   202 				success = LE_MEMORY_ALLOCATION_ERROR;
   203 				delete substitutionFilter;
   204 				return 0;
   205 			}
   206 
   207 			CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, glyphStorage);
   208 			inChars = reordered;
   209 		}
   210 
   211         glyphStorage.allocateGlyphArray(count, rightToLeft, success);
   212         glyphStorage.allocateAuxData(success);
   213 
   214         if (LE_FAILURE(success)) {
   215             delete substitutionFilter;
   216             return 0;
   217         }
   218 
   219         if (rightToLeft) {
   220             out = count - 1;
   221             dir = -1;
   222         }
   223 
   224         for (i = 0; i < count; i += 1, out += dir) {
   225             glyphStorage[out] = (LEGlyphID) inChars[i];
   226             glyphStorage.setAuxData(out, (void *) canonFeatures, success);
   227         }
   228 
   229 		if (reordered != NULL) {
   230 			LE_DELETE_ARRAY(reordered);
   231 		}
   232 
   233         outCharCount = canonGSUBTable->process(glyphStorage, rightToLeft,
   234             scriptTag, langSysTag, NULL, success, substitutionFilter, NULL);
   235 
   236         if (LE_FAILURE(success)) {
   237             delete substitutionFilter;
   238             return 0;
   239         }
   240 
   241         out = (rightToLeft? count - 1 : 0);
   242 
   243         outChars = LE_NEW_ARRAY(LEUnicode, outCharCount);
   244         if (!outChars) {
   245             delete substitutionFilter;
   246             success = LE_MEMORY_ALLOCATION_ERROR;
   247             return 0;
   248         }
   249         for (i = 0; i < outCharCount; i += 1, out += dir) {
   250             outChars[out] = (LEUnicode) LE_GET_GLYPH(glyphStorage[i]);
   251         }
   252 
   253         delete substitutionFilter;
   254     }
   255 
   256     return outCharCount;
   257 }
   258 
   259 le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
   260                                             LEGlyphStorage &glyphStorage, LEErrorCode &success)
   261 {
   262     if (LE_FAILURE(success)) {
   263         return 0;
   264     }
   265 
   266     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
   267         success = LE_ILLEGAL_ARGUMENT_ERROR;
   268         return 0;
   269     }
   270 
   271     LEUnicode *outChars = NULL;
   272     le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success);
   273 
   274     if (outChars != NULL) {
   275         mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success);
   276         LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work...
   277     } else {
   278         mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success);
   279     }
   280 
   281     return glyphStorage.getGlyphCount();
   282 }
   283 
   284 // Input: glyphs
   285 // Output: positions
   286 void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y, LEErrorCode &success)
   287 {
   288     if (LE_FAILURE(success)) {
   289         return;
   290     }
   291 
   292     glyphStorage.allocatePositions(success);
   293 
   294     if (LE_FAILURE(success)) {
   295         return;
   296     }
   297 
   298     le_int32 i, glyphCount = glyphStorage.getGlyphCount();
   299 
   300     for (i = 0; i < glyphCount; i += 1) {
   301         LEPoint advance;
   302 
   303         glyphStorage.setPosition(i, x, y, success);
   304 
   305         fFontInstance->getGlyphAdvance(glyphStorage[i], advance);
   306         x += advance.fX;
   307         y += advance.fY;
   308     }
   309 
   310     glyphStorage.setPosition(glyphCount, x, y, success);
   311 }
   312 
   313 void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/,
   314                                         LEGlyphStorage &glyphStorage, LEErrorCode &success)
   315 {
   316     if (LE_FAILURE(success)) {
   317         return;
   318     }
   319 
   320     if (chars == NULL || offset < 0 || count < 0) {
   321         success = LE_ILLEGAL_ARGUMENT_ERROR;
   322         return;
   323     }
   324 
   325     if (fTypoFlags & 0x1) { /* kerning enabled */
   326       static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG;
   327 
   328       KernTable kt(fFontInstance, getFontTable(kernTableTag));
   329       kt.process(glyphStorage);
   330     }
   331 
   332     // default is no adjustments
   333     return;
   334 }
   335 
   336 void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
   337 {
   338     float xAdjust = 0;
   339     le_int32 p, glyphCount = glyphStorage.getGlyphCount();
   340 
   341     if (LE_FAILURE(success)) {
   342         return;
   343     }
   344 
   345     if (markFilter == NULL) {
   346         success = LE_ILLEGAL_ARGUMENT_ERROR;
   347         return;
   348     }
   349 
   350     float ignore, prev;
   351 
   352     glyphStorage.getGlyphPosition(0, prev, ignore, success);
   353 
   354     for (p = 0; p < glyphCount; p += 1) {
   355         float next, xAdvance;
   356         
   357         glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
   358 
   359         xAdvance = next - prev;
   360         glyphStorage.adjustPosition(p, xAdjust, 0, success);
   361 
   362         if (markFilter->accept(glyphStorage[p])) {
   363             xAdjust -= xAdvance;
   364         }
   365 
   366         prev = next;
   367     }
   368 
   369     glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
   370 }
   371 
   372 void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, le_bool reverse, LEGlyphStorage &glyphStorage, LEGlyphFilter *markFilter, LEErrorCode &success)
   373 {
   374     float xAdjust = 0;
   375     le_int32 c = 0, direction = 1, p;
   376     le_int32 glyphCount = glyphStorage.getGlyphCount();
   377 
   378     if (LE_FAILURE(success)) {
   379         return;
   380     }
   381 
   382     if (markFilter == NULL) {
   383         success = LE_ILLEGAL_ARGUMENT_ERROR;
   384         return;
   385     }
   386 
   387     if (reverse) {
   388         c = glyphCount - 1;
   389         direction = -1;
   390     }
   391 
   392     float ignore, prev;
   393 
   394     glyphStorage.getGlyphPosition(0, prev, ignore, success);
   395 
   396     for (p = 0; p < charCount; p += 1, c += direction) {
   397         float next, xAdvance;
   398         
   399         glyphStorage.getGlyphPosition(p + 1, next, ignore, success);
   400 
   401         xAdvance = next - prev;
   402         glyphStorage.adjustPosition(p, xAdjust, 0, success);
   403 
   404         if (markFilter->accept(chars[c])) {
   405             xAdjust -= xAdvance;
   406         }
   407 
   408         prev = next;
   409     }
   410 
   411     glyphStorage.adjustPosition(glyphCount, xAdjust, 0, success);
   412 }
   413 
   414 const void *LayoutEngine::getFontTable(LETag tableTag) const
   415 {
   416     return fFontInstance->getFontTable(tableTag);
   417 }
   418 
   419 void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror,
   420                                     LEGlyphStorage &glyphStorage, LEErrorCode &success)
   421 {
   422     if (LE_FAILURE(success)) {
   423         return;
   424     }
   425 
   426     glyphStorage.allocateGlyphArray(count, reverse, success);
   427 
   428     DefaultCharMapper charMapper(TRUE, mirror);
   429 
   430     fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, glyphStorage);
   431 }
   432 
   433 // Input: characters, font?
   434 // Output: glyphs, positions, char indices
   435 // Returns: number of glyphs
   436 le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
   437                               float x, float y, LEErrorCode &success)
   438 {
   439     if (LE_FAILURE(success)) {
   440         return 0;
   441     }
   442 
   443     if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) {
   444         success = LE_ILLEGAL_ARGUMENT_ERROR;
   445         return 0;
   446     }
   447 
   448     // 1922 mlyl: get the glyph ID of RAKAR -->
   449     const LEUnicode RAKAR[] = {0xFFFF, 0xD15, 0xD4D, 0xD30, 0xFFFF};
   450     if (fGidOfRA == 0 && mlymScriptCode == fScriptCode) {
   451     	fGidOfRA = -1;  // 0xFFFFFFFF
   452     	TInt noOfGlyphs = layoutChars(
   453     			RAKAR, 		// chars - the input character context
   454     			1,			// the offset of the first character to process	
   455     			3,			// count - the number of characters to process	// offset
   456     			5, 			// max - the number of characters in the input context	// size of text
   457     			FALSE, 		// rightToLeft - TRUE if the characters are in a right to left directional run
   458     			0, 			// start X
   459     			0, 			// start Y
   460     			success);	// result code
   461     	
   462     	if (!LE_FAILURE(success)) {
   463     		fGidOfRA = (*fGlyphStorage)[1];
   464     		(*fGlyphStorage).reset();
   465     	}
   466     }
   467     // <-- 1922 mlyl
   468     
   469     le_int32 glyphCount;
   470     
   471     glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success);
   472     
   473     // 1922 mlyl: put RAKAR left of the preceding glyph -->
   474     if (fGidOfRA != 0 && fGidOfRA != -1 && mlymScriptCode == fScriptCode) {
   475     	fGlyphStorage->forMlylRakar(fGidOfRA);
   476     }
   477     // <-- 1922 mlyl
   478     
   479     positionGlyphs(*fGlyphStorage, x, y, success);
   480     adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success);
   481 
   482     return glyphCount;
   483 }
   484 
   485 void LayoutEngine::reset()
   486 {
   487     fGlyphStorage->reset();
   488 }
   489     
   490 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success)
   491 {
   492   // 3 -> kerning and ligatures
   493   return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success);
   494 }
   495     
   496 LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
   497 {
   498     static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
   499     static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG;
   500 
   501     if (LE_FAILURE(success)) {
   502         return NULL;
   503     }
   504 
   505     const GlyphSubstitutionTableHeader *gsubTable = (const GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag);
   506     LayoutEngine *result = NULL;
   507     LETag scriptTag   = 0x00000000;
   508     LETag languageTag = 0x00000000;
   509 
   510     if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) {
   511         switch (scriptCode) {
   512         case bengScriptCode:
   513         case devaScriptCode:
   514         case gujrScriptCode:
   515         case kndaScriptCode:
   516         case mlymScriptCode:
   517         case oryaScriptCode:
   518         case guruScriptCode:
   519         case tamlScriptCode:
   520         case teluScriptCode:
   521             result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
   522             break;
   523 
   524         case arabScriptCode:
   525             result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
   526             break;
   527 
   528         case haniScriptCode:
   529             languageTag = OpenTypeLayoutEngine::getLangSysTag(languageCode);
   530 
   531             switch (languageCode) {
   532             case korLanguageCode:
   533             case janLanguageCode:
   534             case zhtLanguageCode:
   535             case zhsLanguageCode:
   536                 if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) {
   537                     result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
   538                     break;
   539                 }
   540 
   541                 // note: falling through to default case.
   542             default:
   543                 result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
   544                 break;
   545             }
   546 
   547             break;
   548 
   549         case khmrScriptCode:
   550             result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
   551             break;
   552 
   553         default:
   554             result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
   555             break;
   556         }
   557     } else {
   558         const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag);
   559 
   560         if (morphTable != NULL) {
   561             result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable);
   562         } else {
   563             switch (scriptCode) {
   564             case bengScriptCode:
   565             case devaScriptCode:
   566             case gujrScriptCode:
   567             case kndaScriptCode:
   568             case mlymScriptCode:
   569             case oryaScriptCode:
   570             case guruScriptCode:
   571             case tamlScriptCode:
   572             case teluScriptCode:
   573             {
   574                 result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
   575                 break;
   576             }
   577 
   578             case arabScriptCode:
   579             //case hebrScriptCode:
   580                 result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
   581                 break;
   582 
   583             //case hebrScriptCode:
   584             //    return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
   585 
   586             case thaiScriptCode:
   587                 result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
   588                 break;
   589 
   590             default:
   591                 result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
   592                 break;
   593             }
   594         }
   595     }
   596 
   597     if (result && result->isBogus()) {
   598         delete result;
   599         result = NULL;
   600     }
   601     if (result == NULL) {
   602         success = LE_MEMORY_ALLOCATION_ERROR;
   603     }
   604 
   605     return result;
   606 }
   607 
   608 LayoutEngine::~LayoutEngine() {
   609     delete fGlyphStorage;
   610 }
   611 
   612 U_NAMESPACE_END