le_int32 HanOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool /*rightToLeft*/, LEUnicode *&/*outChars*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } glyphStorage.allocateGlyphArray(count, FALSE, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { return 0; } // FIXME: do we want to add the 'trad' feature for 'ZHT' and the // 'smpl' feature for 'ZHS'? If we do this, we can remove the exact // flag from the language tag lookups, so we can use these features // with the default LangSys... for (le_int32 i = 0; i < count; i += 1) { glyphStorage.setAuxData(i, features, success); } return count; }
// Input: characters // Output: characters, char indices, tags // Returns: output character count le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&/*outChars*/, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } glyphStorage.adoptGlyphCount(count); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } switch (fScriptCode) { case arabScriptCode: { ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); break; } case hebrScriptCode: HebrewShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); break; } return count; }
le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } le_int32 outCharCount = LayoutEngine::characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); if (LE_FAILURE(success)) { return 0; } glyphStorage.allocateGlyphArray(outCharCount, rightToLeft, success); glyphStorage.allocateAuxData(success); for (le_int32 i = 0; i < outCharCount; i += 1) { glyphStorage.setAuxData(i, (void *) fFeatureList, success); } return outCharCount; }
le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); le_int32 i, dir = 1, out = 0, outCharCount = count; if (rightToLeft) { out = count - 1; dir = -1; } if (canonGSUBTable->coversScript(scriptTag)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); glyphStorage.allocateGlyphArray(count, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { return 0; } for (i = 0; i < count; i += 1, out += dir) { glyphStorage[i] = (LEGlyphID) chars[offset + i]; glyphStorage.setAuxData(i, (void *) canonFeatures, success); } outCharCount = canonGSUBTable->process(glyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, NULL); outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); for (i = 0; i < outCharCount; i += 1) { outChars[i] = (LEUnicode) LE_GET_GLYPH(glyphStorage[i]); } delete substitutionFilter; } return outCharCount; }
// Input: characters // Output: characters, char indices, tags // Returns: output character count le_int32 IndicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } le_int32 worstCase = count * IndicReordering::getWorstCaseExpansion(fScriptCode); outChars = LE_NEW_ARRAY(LEUnicode, worstCase); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } // NOTE: assumes this allocates featureTags... // (probably better than doing the worst case stuff here...) le_int32 outCharCount; if (fVersion2) { outCharCount = IndicReordering::v2process(&chars[offset], count, fScriptCode, outChars, glyphStorage); } else { outCharCount = IndicReordering::reorder(&chars[offset], count, fScriptCode, outChars, glyphStorage, &fMPreFixups, success); } if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } glyphStorage.adoptGlyphCount(outCharCount); return outCharCount; }
le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } // This is the cheapest way to get mark reordering only for Hebrew. // We could just do the mark reordering for all scripts, but most // of them probably don't need it... Another option would be to // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it // would need to do is mark reordering, so that seems like overkill. if (fScriptCode == hebrScriptCode) { outChars = LE_NEW_ARRAY(LEUnicode, count); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); } if (LE_FAILURE(success)) { return 0; } glyphStorage.allocateGlyphArray(count, rightToLeft, success); glyphStorage.allocateAuxData(success); for (le_int32 i = 0; i < count; i += 1) { glyphStorage.setAuxData(i, fFeatureMask, success); } return count; }
// Input: characters // Output: characters, char indices, tags // Returns: output character count le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } outChars = LE_NEW_ARRAY(LEUnicode, count); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } glyphStorage.allocateGlyphArray(count, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); // Note: This processes the *original* character array so we can get context // for the first and last characters. This is OK because only the marks // will have been reordered, and they don't contribute to shaping. ArabicShaping::shape(chars, offset, count, max, rightToLeft, glyphStorage); return count; }
// Input: characters // Output: characters, char indices, tags // Returns: output character count le_int32 TibetanOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } le_int32 worstCase = count * 3; // worst case is 3 for Khmer TODO check if 2 is enough outChars = LE_NEW_ARRAY(LEUnicode, worstCase); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } // NOTE: assumes this allocates featureTags... // (probably better than doing the worst case stuff here...) le_int32 outCharCount = TibetanReordering::reorder(&chars[offset], count, fScriptCode, outChars, glyphStorage); glyphStorage.adoptGlyphCount(outCharCount); return outCharCount; }
le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable; LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); le_int32 i, dir = 1, out = 0, outCharCount = count; if (canonGSUBTable->coversScript(scriptTag)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); const LEUnicode *inChars = &chars[offset]; LEUnicode *reordered = NULL; LEGlyphStorage fakeGlyphStorage; fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); if (LE_FAILURE(success)) { return 0; } // This is the cheapest way to get mark reordering only for Hebrew. // We could just do the mark reordering for all scripts, but most // of them probably don't need it... if (fScriptCode == hebrScriptCode) { reordered = LE_NEW_ARRAY(LEUnicode, count); if (reordered == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); inChars = reordered; } fakeGlyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { return 0; } if (rightToLeft) { out = count - 1; dir = -1; } for (i = 0; i < count; i += 1, out += dir) { fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; fakeGlyphStorage.setAuxData(out, canonFeatures, success); } if (reordered != NULL) { LE_DELETE_ARRAY(reordered); } outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE); out = (rightToLeft? outCharCount - 1 : 0); outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); for (i = 0; i < outCharCount; i += 1, out += dir) { outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); } delete substitutionFilter; } return outCharCount; }
le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } LEReferenceTo<GlyphSubstitutionTableHeader> canonGSUBTable((GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable); LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode); LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode); le_int32 i, dir = 1, out = 0, outCharCount = count; if (canonGSUBTable->coversScript(canonGSUBTable,scriptTag, success) || LE_SUCCESS(success)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); if (substitutionFilter == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } const LEUnicode *inChars = &chars[offset]; LEUnicode *reordered = NULL; LEGlyphStorage fakeGlyphStorage; fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); if (LE_FAILURE(success)) { delete substitutionFilter; return 0; } // This is the cheapest way to get mark reordering only for Hebrew. // We could just do the mark reordering for all scripts, but most // of them probably don't need it... if (fScriptCode == hebrScriptCode) { reordered = LE_NEW_ARRAY(LEUnicode, count); if (reordered == NULL) { delete substitutionFilter; success = LE_MEMORY_ALLOCATION_ERROR; return 0; } CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, reordered, fakeGlyphStorage); inChars = reordered; } fakeGlyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { delete substitutionFilter; return 0; } if (rightToLeft) { out = count - 1; dir = -1; } for (i = 0; i < count; i += 1, out += dir) { fakeGlyphStorage[out] = (LEGlyphID) inChars[i]; fakeGlyphStorage.setAuxData(out, canonFeatures, success); } if (reordered != NULL) { LE_DELETE_ARRAY(reordered); } outCharCount = canonGSUBTable->process(canonGSUBTable, fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, (const GlyphDefinitionTableHeader*)NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); if (LE_FAILURE(success)) { delete substitutionFilter; return 0; } out = (rightToLeft? outCharCount - 1 : 0); /* * The char indices array in fakeGlyphStorage has the correct mapping * back to the original input characters. Save it in glyphStorage. The * subsequent call to glyphStoratge.allocateGlyphArray will keep this * array rather than allocating and initializing a new one. */ glyphStorage.adoptCharIndicesArray(fakeGlyphStorage); outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); if (outChars == NULL) { delete substitutionFilter; success = LE_MEMORY_ALLOCATION_ERROR; return 0; } for (i = 0; i < outCharCount; i += 1, out += dir) { outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); } delete substitutionFilter; } return outCharCount; }
le_int32 HangulOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; } if (chars == NULL || offset < 0 || count < 0 || max < 0 || offset >= max || offset + count > max) { success = LE_ILLEGAL_ARGUMENT_ERROR; return 0; } le_int32 worstCase = count * 3; outChars = LE_NEW_ARRAY(LEUnicode, worstCase); if (outChars == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; return 0; } glyphStorage.allocateGlyphArray(worstCase, rightToLeft, success); glyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { LE_DELETE_ARRAY(outChars); return 0; } le_int32 outCharCount = 0; le_int32 limit = offset + count; le_int32 i = offset; while (i < limit) { le_int32 state = 0; le_int32 inStart = i; le_int32 outStart = outCharCount; while( i < limit) { LEUnicode lead = 0; LEUnicode vowel = 0; LEUnicode trail = 0; int32_t chClass = getCharClass(chars[i], lead, vowel, trail); const StateTransition transition = stateTable[state][chClass]; if (chClass == CC_X) { /* Any character of type X will be stored as a trail jamo */ if ((transition.actionFlags & AF_T) != 0) { outChars[outCharCount] = trail; glyphStorage.setCharIndex(outCharCount, i-offset, success); glyphStorage.setAuxData(outCharCount++, nullFeatures, success); } } else { /* Any Hangul will be fully decomposed. Output the decomposed characters. */ if ((transition.actionFlags & AF_L) != 0) { outChars[outCharCount] = lead; glyphStorage.setCharIndex(outCharCount, i-offset, success); glyphStorage.setAuxData(outCharCount++, ljmoFeatures, success); } if ((transition.actionFlags & AF_V) != 0) { outChars[outCharCount] = vowel; glyphStorage.setCharIndex(outCharCount, i-offset, success); glyphStorage.setAuxData(outCharCount++, vjmoFeatures, success); } if ((transition.actionFlags & AF_T) != 0) { outChars[outCharCount] = trail; glyphStorage.setCharIndex(outCharCount, i-offset, success); glyphStorage.setAuxData(outCharCount++, tjmoFeatures, success); } } state = transition.newState; /* Negative next state means stop. */ if (state < 0) { break; } i += 1; } le_int32 inLength = i - inStart; le_int32 outLength = outCharCount - outStart; /* * See if the syllable can be composed into a single character. There are 5 * possible cases: * * Input Decomposed to Compose to * LV L, V LV * LVT L, V, T LVT * L, V L, V LV, DEL * LV, T L, V, T LVT, DEL * L, V, T L, V, T LVT, DEL, DEL */ if ((inLength >= 1 && inLength <= 3) && (outLength == 2 || outLength == 3)) { LEUnicode syllable = 0x0000; LEUnicode lead = outChars[outStart]; LEUnicode vowel = outChars[outStart + 1]; LEUnicode trail = outLength == 3? outChars[outStart + 2] : TJMO_FIRST; /* * If the composition consumes the whole decomposed syllable, * we can use it. */ if (compose(lead, vowel, trail, syllable) == outLength) { outCharCount = outStart; outChars[outCharCount] = syllable; glyphStorage.setCharIndex(outCharCount, inStart-offset, success); glyphStorage.setAuxData(outCharCount++, nullFeatures, success); /* * Replace the rest of the input characters with DEL. */ for(le_int32 d = inStart + 1; d < i; d += 1) { outChars[outCharCount] = 0xFFFF; glyphStorage.setCharIndex(outCharCount, d - offset, success); glyphStorage.setAuxData(outCharCount++, nullFeatures, success); } } } } glyphStorage.adoptGlyphCount(outCharCount); return outCharCount; }