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