1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
31b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert * (C) Copyright IBM Corp. 1998-2015 - All Rights Reserved
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LETypes.h"
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LEGlyphFilter.h"
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "OpenTypeTables.h"
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "GlyphSubstitutionTables.h"
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "MultipleSubstSubtables.h"
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "GlyphIterator.h"
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "LESwaps.h"
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1759d709d503bab6e2b61931737e662dd293b40578ccorneliusle_uint32 MultipleSubstitutionSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
1985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (LE_FAILURE(success)) {
2085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        return 0;
2185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
2285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    LEGlyphID glyph = glyphIterator->getCurrGlyphID();
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // If there's a filter, we only want to do the
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // substitution if the *input* glyphs doesn't
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // exist.
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    //
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // FIXME: is this always the right thing to do?
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // FIXME: should this only be done for a non-zero
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    //        glyphCount?
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (filter != NULL && filter->accept(glyph)) {
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
3659d709d503bab6e2b61931737e662dd293b40578ccornelius    le_int32 coverageIndex = getGlyphCoverage(base, glyph, success);
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    le_uint16 seqCount = SWAPW(sequenceCount);
381b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    LEReferenceToArrayOf<Offset>
391b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        sequenceTableOffsetArrayRef(base, success, sequenceTableOffsetArray, seqCount);
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
411b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    if (LE_FAILURE(success)) {
421b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert        return 0;
431b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert    }
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (coverageIndex >= 0 && coverageIndex < seqCount) {
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        Offset sequenceTableOffset = SWAPW(sequenceTableOffsetArray[coverageIndex]);
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        const SequenceTable *sequenceTable = (const SequenceTable *) ((char *) this + sequenceTableOffset);
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        le_uint16 glyphCount = SWAPW(sequenceTable->glyphCount);
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (glyphCount == 0) {
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            glyphIterator->setCurrGlyphID(0xFFFF);
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 1;
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (glyphCount == 1) {
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[0]);
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (filter != NULL && ! filter->accept(LE_SET_GLYPH(glyph, substitute))) {
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return 0;
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            glyphIterator->setCurrGlyphID(substitute);
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 1;
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // If there's a filter, make sure all of the output glyphs
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // exist.
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (filter != NULL) {
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                for (le_int32 i = 0; i < glyphCount; i += 1) {
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (! filter->accept(substitute)) {
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        return 0;
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
7485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            LEGlyphID *newGlyphs = glyphIterator->insertGlyphs(glyphCount, success);
7585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            if (LE_FAILURE(success)) {
7685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                return 0;
7785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
7885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            le_int32 insert = 0, direction = 1;
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (glyphIterator->isRightToLeft()) {
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                insert = glyphCount - 1;
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                direction = -1;
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (le_int32 i = 0; i < glyphCount; i += 1) {
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                newGlyphs[insert] = LE_SET_GLYPH(glyph, substitute);
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                insert += direction;
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 1;
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return 0;
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
101