1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  *
24  */
25 
26 /*
27  *
28  * (C) Copyright IBM Corp. 1998-2008 - All Rights Reserved
29  *
30  */
31 
32 #include "LETypes.h"
33 #include "LEGlyphFilter.h"
34 #include "OpenTypeTables.h"
35 #include "GlyphSubstitutionTables.h"
36 #include "MultipleSubstSubtables.h"
37 #include "GlyphIterator.h"
38 #include "LESwaps.h"
39 
40 U_NAMESPACE_BEGIN
41 
process(const LETableReference & base,GlyphIterator * glyphIterator,LEErrorCode & success,const LEGlyphFilter * filter) const42 le_uint32 MultipleSubstitutionSubtable::process(const LETableReference &base, GlyphIterator *glyphIterator, LEErrorCode& success, const LEGlyphFilter *filter) const
43 {
44     if (LE_FAILURE(success)) {
45         return 0;
46     }
47 
48     LEGlyphID glyph = glyphIterator->getCurrGlyphID();
49 
50     // If there's a filter, we only want to do the
51     // substitution if the *input* glyphs doesn't
52     // exist.
53     //
54     // FIXME: is this always the right thing to do?
55     // FIXME: should this only be done for a non-zero
56     //        glyphCount?
57     if (filter != NULL && filter->accept(glyph, success)) {
58         return 0;
59     }
60     if(LE_FAILURE(success)) return 0;
61 
62     le_int32 coverageIndex = getGlyphCoverage(base, glyph, success);
63     le_uint16 seqCount = SWAPW(sequenceCount);
64     LEReferenceToArrayOf<Offset>
65         sequenceTableOffsetArrayRef(base, success, sequenceTableOffsetArray, seqCount);
66 
67     if (LE_FAILURE(success)) {
68         return 0;
69     }
70 
71     if (coverageIndex >= 0 && coverageIndex < seqCount) {
72         Offset sequenceTableOffset = SWAPW(sequenceTableOffsetArray[coverageIndex]);
73         LEReferenceTo<SequenceTable>   sequenceTable(base, success, sequenceTableOffset);
74         if (LE_FAILURE(success)) {
75             return 0;
76         }
77         le_uint16 glyphCount = SWAPW(sequenceTable->glyphCount);
78         LEReferenceToArrayOf<Offset>
79             substituteArrayRef(base, success, sequenceTable->substituteArray, glyphCount);
80 
81         if (glyphCount == 0) {
82             glyphIterator->setCurrGlyphID(0xFFFF);
83             return 1;
84         } else if (glyphCount == 1) {
85             TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[0]);
86 
87             if (filter != NULL && ! filter->accept(LE_SET_GLYPH(glyph, substitute), success)) {
88                 return 0;
89             }
90 
91             glyphIterator->setCurrGlyphID(substitute);
92             return 1;
93         } else {
94             // If there's a filter, make sure all of the output glyphs
95             // exist.
96             if (filter != NULL) {
97                 for (le_int32 i = 0; i < glyphCount; i += 1) {
98                     TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);
99 
100                     if (! filter->accept(substitute, success)) {
101                         return 0;
102                     }
103                 }
104             }
105 
106             LEGlyphID *newGlyphs = glyphIterator->insertGlyphs(glyphCount, success);
107             if (LE_FAILURE(success)) {
108                 return 0;
109             }
110 
111             le_int32 insert = 0, direction = 1;
112 
113             if (glyphIterator->isRightToLeft()) {
114                 insert = glyphCount - 1;
115                 direction = -1;
116             }
117 
118             for (le_int32 i = 0; i < glyphCount; i += 1) {
119                 TTGlyphID substitute = SWAPW(sequenceTable->substituteArray[i]);
120 
121                 newGlyphs[insert] = LE_SET_GLYPH(glyph, substitute);
122                 insert += direction;
123             }
124 
125             return 1;
126         }
127     }
128 
129     return 0;
130 }
131 
132 U_NAMESPACE_END
133