예제 #1
0
void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft,
                                LEUnicode *outChars, LEGlyphStorage &glyphStorage)
{
    LEErrorCode success = LE_NO_ERROR;
    LEReferenceTo<GlyphDefinitionTableHeader> gdefTable(LETableReference::kStaticData, CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen);
    LEReferenceTo<ClassDefinitionTable> classTable = gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success);
    le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount);
    le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount);
    le_int32 i;

    if (combiningClasses == NULL || indices == NULL) {
        if (combiningClasses != NULL) {
            LE_DELETE_ARRAY(combiningClasses);
        }
        if (indices != NULL) {
            LE_DELETE_ARRAY(indices);
        }
        return;
    }

    for (i = 0; i < charCount; i += 1) {
      combiningClasses[i] = classTable->getGlyphClass(classTable, (LEGlyphID) inChars[i], success);
        indices[i] = i;
    }

    for (i = 0; i < charCount; i += 1) {
        if (combiningClasses[i] != 0) {
            le_int32 mark;

            for (mark = i; mark < charCount; mark += 1) {
                if (combiningClasses[mark] == 0) {
                    break;
                }
            }

            sortMarks(indices, combiningClasses, i, mark);
        }
    }

    le_int32 out = 0, dir = 1;

    if (rightToLeft) {
        out = charCount - 1;
        dir = -1;
    }

    for (i = 0; i < charCount; i += 1, out += dir) {
        le_int32 index = indices[i];

        outChars[i] = inChars[index];
        glyphStorage.setCharIndex(out, index, success);
    }

    LE_DELETE_ARRAY(indices);
    LE_DELETE_ARRAY(combiningClasses);
}
예제 #2
0
Paragraph::Paragraph(const LEUnicode chars[], int32_t charCount, const FontRuns *fontRuns, LEErrorCode &status)
  : fParagraphLayout(NULL), fLineCount(0), fLinesMax(0), fLinesGrow(LINE_GROW), fLines(NULL), fChars(NULL),
    fLineHeight(-1), fAscent(-1), fWidth(-1), fHeight(-1)
{
	if (LE_FAILURE(status)) {
		return;
	}

	LocaleRuns *locales = NULL;

    fChars = LE_NEW_ARRAY(LEUnicode, charCount);
    LE_ARRAY_COPY(fChars, chars, charCount);

    fParagraphLayout = new ParagraphLayout(fChars, charCount, fontRuns, NULL, NULL, locales, UBIDI_DEFAULT_LTR, FALSE, status);

	if (LE_FAILURE(status)) {
		return;
	}

    le_int32 ascent  = fParagraphLayout->getAscent();
    le_int32 descent = fParagraphLayout->getDescent();
    le_int32 leading = fParagraphLayout->getLeading();

    fLineHeight = ascent + descent + leading;
    fAscent     = ascent;
}
// "glyphs", "indices" -> glyphs, indices
le_int32 UnicodeArabicOpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
    if (LE_FAILURE(success)) {
        return 0;
    }

    // FIXME: we could avoid the memory allocation and copy if we
    // made a clone of mapCharsToGlyphs which took the fake glyphs
    // directly.
    le_int32 tempGlyphCount = tempGlyphStorage.getGlyphCount();
    LEUnicode *tempChars = LE_NEW_ARRAY(LEUnicode, tempGlyphCount);

    if (tempChars == NULL) {
        success = LE_MEMORY_ALLOCATION_ERROR;
        return 0;
    }

    for (le_int32 i = 0; i < tempGlyphCount; i += 1) {
        tempChars[i] = (LEUnicode) LE_GET_GLYPH(tempGlyphStorage[i]);
    }

    glyphStorage.adoptCharIndicesArray(tempGlyphStorage);

    ArabicOpenTypeLayoutEngine::mapCharsToGlyphs(tempChars, 0, tempGlyphCount, FALSE, TRUE, glyphStorage, success);

    LE_DELETE_ARRAY(tempChars);

    return tempGlyphCount;
}
예제 #4
0
void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft,
                                LEUnicode *outChars, LEGlyphStorage &glyphStorage)
{
    const GlyphDefinitionTableHeader *gdefTable = (const GlyphDefinitionTableHeader *) glyphDefinitionTable;
    const ClassDefinitionTable *classTable = gdefTable->getMarkAttachClassDefinitionTable();
    le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount);
    le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount);
    LEErrorCode status = LE_NO_ERROR;
    le_int32 i;

    for (i = 0; i < charCount; i += 1) {
        combiningClasses[i] = classTable->getGlyphClass((LEGlyphID) inChars[i]);
        indices[i] = i;
    }

    for (i = 0; i < charCount; i += 1) {
        if (combiningClasses[i] != 0) {
            le_int32 mark;

            for (mark = i; mark < charCount; mark += 1) {
                if (combiningClasses[mark] == 0) {
                    break;
                }
            }

            sortMarks(indices, combiningClasses, i, mark);
        }
    }

    le_int32 out = 0, dir = 1;

    if (rightToLeft) {
        out = charCount - 1;
        dir = -1;
    }

    for (i = 0; i < charCount; i += 1, out += dir) {
        le_int32 index = indices[i];

        outChars[i] = inChars[index];
        glyphStorage.setCharIndex(out, index, status);
    }

    LE_DELETE_ARRAY(indices);
    LE_DELETE_ARRAY(combiningClasses);
}
예제 #5
0
void
FontTableCache::initialize()
{
    fTableCache = LE_NEW_ARRAY(FontTableCacheEntry, fTableCacheSize);

    if (fTableCache == NULL) {
        fTableCacheSize = 0;
        return;
    }
}
예제 #6
0
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;
}
예제 #7
0
FontTableCache::FontTableCache()
    : fTableCacheCurr(0), fTableCacheSize(TABLE_CACHE_INIT)
{
    fTableCache = LE_NEW_ARRAY(FontTableCacheEntry, fTableCacheSize);

    if (fTableCache == NULL) {
        fTableCacheSize = 0;
        return;
    }

    for (int i = 0; i < fTableCacheSize; i += 1) {
        fTableCache[i].tag   = 0;
        fTableCache[i].table = NULL;
    }
}
// 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;
}
예제 #10
0
// Input: characters (0..max provided for context)
// Output: glyphs, char indices
// Returns: the glyph count
// NOTE: this assumes that ThaiShaping::compose will allocate the outChars array...
le_int32 ThaiLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool /*rightToLeft*/, 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;
    }

    LEUnicode *outChars;
    le_int32 glyphCount;
    
    // This is enough room for the worst-case expansion
    // (it says here...)
    outChars = LE_NEW_ARRAY(LEUnicode, count * 2);

    if (outChars == NULL) {
        success = LE_MEMORY_ALLOCATION_ERROR;
        return 0;
    }

    glyphStorage.allocateGlyphArray(count * 2, FALSE, success);

    if (LE_FAILURE(success)) {
        LE_DELETE_ARRAY(outChars);
        success = LE_MEMORY_ALLOCATION_ERROR;
        return 0;
    }

    glyphCount = ThaiShaping::compose(chars, offset, count, fGlyphSet, fErrorChar, outChars, glyphStorage);
    mapCharsToGlyphs(outChars, 0, glyphCount, FALSE, FALSE, glyphStorage, success);

    LE_DELETE_ARRAY(outChars);

    glyphStorage.adoptGlyphCount(glyphCount);
    return glyphCount;
}
예제 #11
0
// 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;
}
예제 #12
0
// 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;
}
예제 #13
0
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;
}
예제 #14
0
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;
}
예제 #15
0
LookupProcessor::LookupProcessor(const char *baseAddress,
        Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
        LETag scriptTag, LETag languageTag, const FeatureMap *featureMap,
        le_int32 featureMapCount, le_bool orderFeatures)
    : lookupListTable(NULL), featureListTable(NULL), lookupSelectArray(NULL),
      lookupOrderArray(NULL), lookupOrderCount(0)
{
    const ScriptListTable *scriptListTable = NULL;
    const LangSysTable *langSysTable = NULL;
    le_uint16 featureCount = 0;
    le_uint16 lookupListCount = 0;
    le_uint16 requiredFeatureIndex;

    if (scriptListOffset != 0) {
        scriptListTable = (const ScriptListTable *) (baseAddress + scriptListOffset);
        langSysTable = scriptListTable->findLanguage(scriptTag, languageTag);

        if (langSysTable != 0) {
            featureCount = SWAPW(langSysTable->featureCount);
        }
    }

    if (featureListOffset != 0) {
        featureListTable = (const FeatureListTable *) (baseAddress + featureListOffset);
    }

    if (lookupListOffset != 0) {
        lookupListTable = (const LookupListTable *) (baseAddress + lookupListOffset);
        lookupListCount = SWAPW(lookupListTable->lookupCount);
    }

    if (langSysTable == NULL || featureListTable == NULL || lookupListTable == NULL ||
        featureCount == 0 || lookupListCount == 0) {
        return;
    }

    requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);

    lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);

    for (int i = 0; i < lookupListCount; i += 1) {
        lookupSelectArray[i] = 0;
    }

    le_int32 count, order = 0;
    le_int32 featureReferences = 0;
    const FeatureTable *featureTable = NULL;
    LETag featureTag;

    const FeatureTable *requiredFeatureTable = NULL;
    LETag requiredFeatureTag = 0x00000000U;

    // Count the total number of lookups referenced by all features. This will
    // be the maximum number of entries in the lookupOrderArray. We can't use
    // lookupListCount because some lookups might be referenced by more than
    // one feature.
    for (le_int32 feature = 0; feature < featureCount; feature += 1) {
        le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);

        featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);
        featureReferences += SWAPW(featureTable->lookupCount);
    }

    if (requiredFeatureIndex != 0xFFFF) {
        requiredFeatureTable = featureListTable->getFeatureTable(requiredFeatureIndex, &requiredFeatureTag);
        featureReferences += SWAPW(featureTable->lookupCount);
    }

    lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);

    for (le_int32 f = 0; f < featureMapCount; f += 1) {
        FeatureMap fm = featureMap[f];
        count = 0;

        // If this is the required feature, add its lookups
        if (requiredFeatureTag == fm.tag) {
            count += selectLookups(requiredFeatureTable, fm.mask, order);
        }

        if (orderFeatures) {
            // If we added lookups from the required feature, sort them
            if (count > 1) {
                OpenTypeUtilities::sort(lookupOrderArray, order);
            }

            for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
                le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);

                // don't add the required feature to the list more than once...
                // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
                if (featureIndex == requiredFeatureIndex) {
                    continue;
                }

                featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);

                if (featureTag == fm.tag) {
                    count += selectLookups(featureTable, fm.mask, order + count);
                }
            }

            if (count > 1) {
                OpenTypeUtilities::sort(&lookupOrderArray[order], count);
            }

            order += count;
        } else {
            for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
                le_uint16 featureIndex = SWAPW(langSysTable->featureIndexArray[feature]);

                // don't add the required feature to the list more than once...
                // NOTE: This check is commented out because the spec. says that
                // the required feature won't be in the feature list, and because
                // any duplicate entries will be removed below.
#if 0
                if (featureIndex == requiredFeatureIndex) {
                    continue;
                }
#endif

                featureTable = featureListTable->getFeatureTable(featureIndex, &featureTag);

                if (featureTag == fm.tag) {
                    order += selectLookups(featureTable, fm.mask, order);
                }
            }
        }
    }

    if (!orderFeatures && (order > 1)) {
        OpenTypeUtilities::sort(lookupOrderArray, order);

        // If there's no specified feature order,
        // we will apply the lookups in the order
        // that they're in the font. If a particular
        // lookup may be referenced by more than one feature,
        // it will apprear in the lookupOrderArray more than
        // once, so remove any duplicate entries in the sorted array.
        le_int32 out = 1;

        for (le_int32 in = 1; in < order; in += 1) {
            if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
                if (out != in) {
                    lookupOrderArray[out] = lookupOrderArray[in];
                }

                out += 1;
            }
        }

        order = out;
    }

    lookupOrderCount = order;
}
예제 #16
0
void MPreFixups::apply(LEGlyphStorage &glyphStorage, LEErrorCode& leSuccess)
{
    if (LE_FAILURE(leSuccess)) {
        return;
    }

    for (le_int32 fixup = 0; fixup < fFixupCount; fixup += 1) {
        le_int32 baseIndex = fFixupData[fixup].fBaseIndex;
        le_int32 mpreIndex = fFixupData[fixup].fMPreIndex;
        le_int32 mpreLimit = mpreIndex + 1;

        while (glyphStorage[baseIndex] == 0xFFFF || glyphStorage[baseIndex] == 0xFFFE) {
            baseIndex -= 1;
        }

        while (glyphStorage[mpreLimit] == 0xFFFF || glyphStorage[mpreLimit] == 0xFFFE) {
            mpreLimit += 1;
        }

        if (mpreLimit == baseIndex) {
            continue;
        }

        LEErrorCode success = LE_NO_ERROR;
        le_int32   mpreCount = mpreLimit - mpreIndex;
        le_int32   moveCount = baseIndex - mpreLimit;
        le_int32   mpreDest  = baseIndex - mpreCount;
        LEGlyphID *mpreSave  = LE_NEW_ARRAY(LEGlyphID, mpreCount);
        le_int32  *indexSave = LE_NEW_ARRAY(le_int32, mpreCount);

        if (mpreSave == NULL || indexSave == NULL) {
            LE_DELETE_ARRAY(mpreSave);
            LE_DELETE_ARRAY(indexSave);
            success = LE_MEMORY_ALLOCATION_ERROR;
            return;
        }

        le_int32   i;

        for (i = 0; i < mpreCount; i += 1) {
            mpreSave[i]  = glyphStorage[mpreIndex + i];
            indexSave[i] = glyphStorage.getCharIndex(mpreIndex + i, success); //charIndices[mpreIndex + i];
        }

        for (i = 0; i < moveCount; i += 1) {
            LEGlyphID glyph = glyphStorage[mpreLimit + i];
            le_int32 charIndex = glyphStorage.getCharIndex(mpreLimit + i, success);

            glyphStorage[mpreIndex + i] = glyph;
            glyphStorage.setCharIndex(mpreIndex + i, charIndex, success);
        }

        for (i = 0; i < mpreCount; i += 1) {
            glyphStorage[mpreDest + i] = mpreSave[i];
            glyphStorage.setCharIndex(mpreDest, indexSave[i], success);
        }

        LE_DELETE_ARRAY(indexSave);
        LE_DELETE_ARRAY(mpreSave);
    }
}
예제 #17
0
MPreFixups::MPreFixups(le_int32 charCount)
    : fFixupData(NULL), fFixupCount(0)
{
    fFixupData = LE_NEW_ARRAY(FixupData, charCount);
}
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;
}
예제 #19
0
파일: paragraph.cpp 프로젝트: winlibs/icu4c
Paragraph::Paragraph(const LEUnicode chars[], int32_t charCount, const FontRuns *fontRuns, LEErrorCode &status)
  : fParagraphLayout(NULL), fParagraphCount(0), fParagraphMax(PARA_GROW), fParagraphGrow(PARA_GROW),
    fLineCount(0), fLinesMax(LINE_GROW), fLinesGrow(LINE_GROW), fLines(NULL), fChars(NULL),
    fLineHeight(-1), fAscent(-1), fWidth(-1), fHeight(-1), fParagraphLevel(UBIDI_DEFAULT_LTR)
{
    static const LEUnicode separators[] = {CH_LF, CH_CR, CH_LSEP, CH_PSEP, 0x0000};

	if (LE_FAILURE(status)) {
		return;
	}

    le_int32 ascent  = 0;
    le_int32 descent = 0;
    le_int32 leading = 0;

	LocaleRuns *locales = NULL;
    FontRuns fr(0);

    fLines = LE_NEW_ARRAY(const ParagraphLayout::Line *, fLinesMax);
    fParagraphLayout = LE_NEW_ARRAY(ParagraphLayout *, fParagraphMax);

    fChars = LE_NEW_ARRAY(LEUnicode, charCount + 1);
    LE_ARRAY_COPY(fChars, chars, charCount);
    fChars[charCount] = 0;

    LEUnicode *pStart = &fChars[0];

    while (*pStart != 0) {
        LEUnicode *pEnd = u_strpbrk(pStart, separators);
        le_int32 pAscent, pDescent, pLeading;
        ParagraphLayout *paragraphLayout = NULL;

        if (pEnd == NULL) {
            pEnd = &fChars[charCount];
        }

        if (pEnd != pStart) {
            subsetFontRuns(fontRuns, pStart - fChars, pEnd - fChars, &fr);

            paragraphLayout = new ParagraphLayout(pStart, pEnd - pStart, &fr, NULL, NULL, locales, fParagraphLevel, FALSE, status);

            if (LE_FAILURE(status)) {
                delete paragraphLayout;
                break; // return? something else?
            }

            if (fParagraphLevel == UBIDI_DEFAULT_LTR) {
                fParagraphLevel = paragraphLayout->getParagraphLevel();
            }

            pAscent  = paragraphLayout->getAscent();
            pDescent = paragraphLayout->getDescent();
            pLeading = paragraphLayout->getLeading();

            if (pAscent > ascent) {
                ascent = pAscent;
            }

            if (pDescent > descent) {
                descent = pDescent;
            }

            if (pLeading > leading) {
                leading = pLeading;
            }
        }

        if (fParagraphCount >= fParagraphMax) {
            fParagraphLayout = (ParagraphLayout **) LE_GROW_ARRAY(fParagraphLayout, fParagraphMax + fParagraphGrow);
            fParagraphMax += fParagraphGrow;
        }

        fParagraphLayout[fParagraphCount++] = paragraphLayout;

        if (*pEnd == 0) {
            break;
        }

        pStart = skipLineEnd(pEnd);
    }

    fLineHeight = ascent + descent + leading;
    fAscent     = ascent;
}
예제 #20
0
LookupProcessor::LookupProcessor(const LETableReference &baseAddress,
        Offset scriptListOffset, Offset featureListOffset, Offset lookupListOffset,
        LETag scriptTag, LETag languageTag, const FeatureMap *featureMap, le_int32 featureMapCount, le_bool orderFeatures,
        LEErrorCode& success)
    : lookupListTable(), featureListTable(), lookupSelectArray(NULL), lookupSelectCount(0),
      lookupOrderArray(NULL), lookupOrderCount(0), fReference(baseAddress)
{
  LEReferenceTo<ScriptListTable> scriptListTable;
  LEReferenceTo<LangSysTable> langSysTable;
    le_uint16 featureCount = 0;
    le_uint16 lookupListCount = 0;
    le_uint16 requiredFeatureIndex = 0xFFFF;

    if (LE_FAILURE(success)) {
        return;
    }

    if (scriptListOffset != 0) {
      scriptListTable = LEReferenceTo<ScriptListTable>(baseAddress, success, scriptListOffset);
      langSysTable = scriptListTable->findLanguage(scriptListTable, scriptTag, languageTag, success);

      if (langSysTable.isValid() && LE_SUCCESS(success)) {
        featureCount = SWAPW(langSysTable->featureCount);
      }
    }

    if (featureListOffset != 0) {
      featureListTable = LEReferenceTo<FeatureListTable>(baseAddress, success, featureListOffset);
    }

    if (lookupListOffset != 0) {
      lookupListTable = LEReferenceTo<LookupListTable>(baseAddress,success, lookupListOffset);
      if(LE_SUCCESS(success) && lookupListTable.isValid()) {
        lookupListCount = SWAPW(lookupListTable->lookupCount);
      }
    }

    if (langSysTable.isEmpty() || featureListTable.isEmpty() || lookupListTable.isEmpty() ||
        featureCount == 0 || lookupListCount == 0) {
        return;
    }

    if(langSysTable.isValid()) {
      requiredFeatureIndex = SWAPW(langSysTable->reqFeatureIndex);
    }

    lookupSelectArray = LE_NEW_ARRAY(FeatureMask, lookupListCount);
    if (lookupSelectArray == NULL) {
        success = LE_MEMORY_ALLOCATION_ERROR;
        return;
    }

    for (int i = 0; i < lookupListCount; i += 1) {
        lookupSelectArray[i] = 0;
    }

    lookupSelectCount = lookupListCount;

    le_int32 count, order = 0;
    le_uint32 featureReferences = 0;
    LEReferenceTo<FeatureTable> featureTable;
    LETag featureTag;

    LEReferenceTo<FeatureTable> requiredFeatureTable;
    LETag requiredFeatureTag = 0x00000000U;

    // Count the total number of lookups referenced by all features. This will
    // be the maximum number of entries in the lookupOrderArray. We can't use
    // lookupListCount because some lookups might be referenced by more than
    // one feature.
    if(featureListTable.isValid() && LE_SUCCESS(success)) {
      LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);

      for (le_uint32 feature = 0; LE_SUCCESS(success)&&(feature < featureCount); feature += 1) {
        le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature, success));

        featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex,  &featureTag, success);
        if (!featureTable.isValid() || LE_FAILURE(success)) {
          continue;
        }
        featureReferences += SWAPW(featureTable->lookupCount);
      }
    }

    if (!featureTable.isValid() || LE_FAILURE(success)) {
        success = LE_INTERNAL_ERROR;
        return;
    }

    if (requiredFeatureIndex != 0xFFFF) {
      requiredFeatureTable = featureListTable->getFeatureTable(featureListTable, requiredFeatureIndex, &requiredFeatureTag, success);
      if (LE_FAILURE(success)) return;
      featureReferences += SWAPW(requiredFeatureTable->lookupCount);
    }

    lookupOrderArray = LE_NEW_ARRAY(le_uint16, featureReferences);
    if (lookupOrderArray == NULL) {
        success = LE_MEMORY_ALLOCATION_ERROR;
        return;
    }
    lookupOrderCount = featureReferences;

    for (le_int32 f = 0; f < featureMapCount; f += 1) {
        FeatureMap fm = featureMap[f];
        count = 0;

        // If this is the required feature, add its lookups
        if (requiredFeatureTag == fm.tag) {
          count += selectLookups(requiredFeatureTable, fm.mask, order, success);
        }

        if (orderFeatures) {
            // If we added lookups from the required feature, sort them
            if (count > 1) {
                OpenTypeUtilities::sort(lookupOrderArray, order);
            }

            for (le_uint16 feature = 0; feature < featureCount; feature += 1) {
              LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
              if (LE_FAILURE(success)) { continue; }
              le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));

                // don't add the required feature to the list more than once...
                // TODO: Do we need this check? (Spec. says required feature won't be in feature list...)
                if (featureIndex == requiredFeatureIndex) {
                    continue;
                }

                featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
                if (LE_FAILURE(success)) continue;
                if (featureTag == fm.tag) {
                  count += selectLookups(featureTable, fm.mask, order + count, success);
                }
            }

            if (count > 1) {
                OpenTypeUtilities::sort(&lookupOrderArray[order], count);
            }

            order += count;
        } else if(langSysTable.isValid()) {
          LEReferenceToArrayOf<le_uint16> featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount);
          for (le_uint16 feature = 0; LE_SUCCESS(success)&& (feature < featureCount); feature += 1) {
            le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success));

                // don't add the required feature to the list more than once...
                // NOTE: This check is commented out because the spec. says that
                // the required feature won't be in the feature list, and because
                // any duplicate entries will be removed below.
#if 0
                if (featureIndex == requiredFeatureIndex) {
                    continue;
                }
#endif

                featureTable = featureListTable->getFeatureTable(featureListTable, featureIndex, &featureTag, success);
                if (LE_FAILURE(success)) continue;
                if (featureTag == fm.tag) {
                  order += selectLookups(featureTable, fm.mask, order, success);
                }
            }
        }
    }

    if (!orderFeatures && (order > 1)) {
        OpenTypeUtilities::sort(lookupOrderArray, order);

        // If there's no specified feature order,
        // we will apply the lookups in the order
        // that they're in the font. If a particular
        // lookup may be referenced by more than one feature,
        // it will apprear in the lookupOrderArray more than
        // once, so remove any duplicate entries in the sorted array.
        le_int32 out = 1;

        for (le_int32 in = 1; in < order; in += 1) {
            if (lookupOrderArray[out - 1] != lookupOrderArray[in]) {
                if (out != in) {
                    lookupOrderArray[out] = lookupOrderArray[in];
                }

                out += 1;
            }
        }

        order = out;
    }

    lookupOrderCount = order;
}
예제 #21
0
const UChar *UnicodeReader::readFile(const char *fileName, GUISupport *guiSupport, int32_t &charCount)
{
    FILE *f;
    int32_t fileSize;
    
    UChar *charBuffer;
    char *byteBuffer;
    char startBytes[4] = {'\xA5', '\xA5', '\xA5', '\xA5'};
    char errorMessage[128];
    const char *cp = "";
    int32_t signatureLength = 0;
    
    f = fopen(fileName, "rb");
    
    if( f == NULL ) {
        sprintf(errorMessage,"Couldn't open %s: %s \n", fileName, strerror(errno));
        guiSupport->postErrorMessage(errorMessage, "Text File Error");
        return 0;
    }
    
    fseek(f, 0, SEEK_END);
    fileSize = ftell(f);

    fseek(f, 0, SEEK_SET);
    fread(startBytes, sizeof(char), 4, f);

    if (startBytes[0] == '\xFE' && startBytes[1] == '\xFF') {
        cp = "UTF-16BE";
        signatureLength = 2;
    } else if (startBytes[0] == '\xFF' && startBytes[1] == '\xFE') {
        if (startBytes[2] == '\x00' && startBytes[3] == '\x00') {
            cp = "UTF-32LE";
            signatureLength = 4;
        } else {
            cp = "UTF-16LE";
            signatureLength = 2;
        }
    } else if (startBytes[0] == '\xEF' && startBytes[1] == '\xBB' && startBytes[2] == '\xBF') {
        cp = "UTF-8";
        signatureLength = 3;
    } else if (startBytes[0] == '\x0E' && startBytes[1] == '\xFE' && startBytes[2] == '\xFF') {
        cp = "SCSU";
        signatureLength = 3;
    } else if (startBytes[0] == '\x00' && startBytes[1] == '\x00' &&
        startBytes[2] == '\xFE' && startBytes[3] == '\xFF') {
        cp = "UTF-32BE";
        signatureLength = 4;
    } else {
        sprintf(errorMessage, "Couldn't detect the encoding of %s: (%2.2X, %2.2X, %2.2X, %2.2X)\n", fileName,
                    BYTE(startBytes[0]), BYTE(startBytes[1]), BYTE(startBytes[2]), BYTE(startBytes[3]));
        guiSupport->postErrorMessage(errorMessage, "Text File Error");
        fclose(f);
        return 0;
    }
        
    fileSize -= signatureLength;
    fseek(f, signatureLength, SEEK_SET);
    byteBuffer = new char[fileSize];
    
    if(byteBuffer == 0) {
        sprintf(errorMessage,"Couldn't get memory for reading %s: %s \n", fileName, strerror(errno));
        guiSupport->postErrorMessage(errorMessage, "Text File Error");
        fclose(f);
        return 0;
    }
    
    fread(byteBuffer, sizeof(char), fileSize, f);
    if( ferror(f) ) {
        sprintf(errorMessage,"Couldn't read %s: %s \n", fileName, strerror(errno));
        guiSupport->postErrorMessage(errorMessage, "Text File Error");
        fclose(f);
        delete[] byteBuffer;
        return 0;
    }
    fclose(f);
    
    UnicodeString myText(byteBuffer, fileSize, cp);

    delete[] byteBuffer;
    
    charCount = myText.length();
    charBuffer = LE_NEW_ARRAY(UChar, charCount + 1);
    if(charBuffer == 0) {
        sprintf(errorMessage,"Couldn't get memory for reading %s: %s \n", fileName, strerror(errno));
        guiSupport->postErrorMessage(errorMessage, "Text File Error");
        return 0;
    }
    
    myText.extract(0, myText.length(), charBuffer);
    charBuffer[charCount] = 0;    // NULL terminate for easier reading in the debugger
    
    return charBuffer;
}