Example #1
0
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;
}
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;
}
Example #3
0
void ArabicShaping::adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage)
{
    LEErrorCode success = LE_NO_ERROR;
    FeatureMask featureMask = (FeatureMask) glyphStorage.getAuxData(outIndex, success);
    FeatureMask shape = featureMask & SHAPE_MASK;

    shape >>= shapeOffset;

    glyphStorage.setAuxData(outIndex, ((featureMask & ~SHAPE_MASK) | shape), success);
}
void IndicReordering::applyPresentationForms(LEGlyphStorage &glyphStorage, le_int32 count)
{
    LEErrorCode success = LE_NO_ERROR;

//  This sets us up for 2nd pass of glyph substitution as well as setting the feature masks for the
//  GPOS table lookups

    for ( le_int32 i = 0 ; i < count ; i++ ) {
        glyphStorage.setAuxData(i, ( presentationFormsMask | positioningFormsMask ), success);
    }

}
Example #5
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;
}
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;
}
Example #7
0
void ArabicShaping::shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax,
                          le_bool rightToLeft, LEGlyphStorage &glyphStorage)
{
    // iterate in logical order, store tags in visible order
    // 
    // the effective right char is the most recently encountered 
    // non-transparent char
    //
    // four boolean states:
    //   the effective right char shapes
    //   the effective right char causes left shaping
    //   the current char shapes
    //   the current char causes right shaping
    // 
    // if both cause shaping, then
    //   shaper.shape(errout, 2) (isolate to initial, or final to medial)
    //   shaper.shape(out, 1) (isolate to final)

    ShapeType rightType = ST_NOSHAPE_NONE, leftType = ST_NOSHAPE_NONE;
    LEErrorCode success = LE_NO_ERROR;
    le_int32 i;

    for (i = offset - 1; i >= 0; i -= 1) {
        rightType = getShapeType(chars[i]);
        
        if (rightType != ST_TRANSPARENT) {
            break;
        }
    }

    for (i = offset + charCount; i < charMax; i += 1) {
        leftType = getShapeType(chars[i]);

        if (leftType != ST_TRANSPARENT) {
            break;
        }
    }

    // erout is effective right logical index
    le_int32 erout = -1;
    le_bool rightShapes = FALSE;
    le_bool rightCauses = (rightType & MASK_SHAPE_LEFT) != 0;
    le_int32 in, e, out = 0, dir = 1;

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

    for (in = offset, e = offset + charCount; in < e; in += 1, out += dir) {
        LEUnicode c = chars[in];
        ShapeType t = getShapeType(c);

        if (t == ST_NOSHAPE_NONE) {
            glyphStorage.setAuxData(out, NO_FEATURES, success);
        } else {
            glyphStorage.setAuxData(out, ISOL_FEATURES, success);
        }


        if ((t & MASK_TRANSPARENT) != 0) {
            continue;
        }

        le_bool curShapes = (t & MASK_NOSHAPE) == 0;
        le_bool curCauses = (t & MASK_SHAPE_RIGHT) != 0;

        if (rightCauses && curCauses) {
            if (rightShapes) {
                adjustTags(erout, 2, glyphStorage);
            }

            if (curShapes) {
                adjustTags(out, 1, glyphStorage);
            }
        }

        rightShapes = curShapes;
        rightCauses = (t & MASK_SHAPE_LEFT) != 0;
        erout = out;
    }

    if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) {
        adjustTags(erout, 2, glyphStorage);
    }
}
Example #8
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;
}
Example #9
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;
}
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;
}