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 * (C) Copyright IBM Corp. and others 1998 - 2013 - All Rights Reserved
28 *
29 */
30
31#include "LETypes.h"
32#include "LayoutTables.h"
33#include "MorphTables.h"
34#include "SubtableProcessor2.h"
35#include "IndicRearrangementProcessor2.h"
36#include "ContextualGlyphSubstProc2.h"
37#include "LigatureSubstProc2.h"
38#include "NonContextualGlyphSubstProc2.h"
39#include "ContextualGlyphInsertionProc2.h"
40#include "LEGlyphStorage.h"
41#include "LESwaps.h"
42
43U_NAMESPACE_BEGIN
44
45void MorphTableHeader2::process(const LEReferenceTo<MorphTableHeader2> &base, LEGlyphStorage &glyphStorage,
46                                le_int32 typoFlags, LEErrorCode &success) const
47{
48  if(LE_FAILURE(success)) return;
49
50  le_uint32 chainCount = SWAPL(this->nChains);
51  LEReferenceTo<ChainHeader2> chainHeader(base, success, &chains[0]);
52  /* chainHeader and subtableHeader are implemented as a moving pointer rather than an array dereference
53   * to (slightly) reduce code churn. However, must be careful to preincrement them the 2nd time through.
54   * We don't want to increment them at the end of the loop, as that would attempt to dereference
55   * out of range memory.
56   */
57  le_uint32 chain;
58
59  for (chain = 0; LE_SUCCESS(success) && (chain < chainCount); chain++) {
60        if (chain>0) {
61          le_uint32 chainLength = SWAPL(chainHeader->chainLength);
62          if (chainLength & 0x03) { // incorrect alignment for 32 bit tables
63              success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any
64              return;
65          }
66          chainHeader.addOffset(chainLength, success); // Don't increment the first time
67        }
68        FeatureFlags flag = SWAPL(chainHeader->defaultFlags);
69        le_uint32 nFeatureEntries = SWAPL(chainHeader->nFeatureEntries);
70        le_uint32 nSubtables = SWAPL(chainHeader->nSubtables);
71        LEReferenceTo<MorphSubtableHeader2> subtableHeader(chainHeader,
72              success, (const MorphSubtableHeader2 *)&chainHeader->featureTable[nFeatureEntries]);
73        le_uint32 subtable;
74        if(LE_FAILURE(success)) break; // malformed table
75
76        if (typoFlags != 0) {
77           le_uint32 featureEntry;
78           LEReferenceToArrayOf<FeatureTableEntry> featureTableRef(chainHeader, success, &chainHeader->featureTable[0], nFeatureEntries);
79           if(LE_FAILURE(success)) break;
80            // Feature subtables
81            for (featureEntry = 0; featureEntry < nFeatureEntries; featureEntry++) {
82                const FeatureTableEntry &featureTableEntry = featureTableRef(featureEntry, success);
83                le_int16 featureType = SWAPW(featureTableEntry.featureType);
84                le_int16 featureSetting = SWAPW(featureTableEntry.featureSetting);
85                le_uint32 enableFlags = SWAPL(featureTableEntry.enableFlags);
86                le_uint32 disableFlags = SWAPL(featureTableEntry.disableFlags);
87                switch (featureType) {
88                    case ligaturesType:
89                        if ((typoFlags & LE_Ligatures_FEATURE_ENUM ) && (featureSetting ^ 0x1)){
90                            flag &= disableFlags;
91                            flag |= enableFlags;
92                        } else {
93                            if (((typoFlags & LE_RLIG_FEATURE_FLAG) && featureSetting == requiredLigaturesOnSelector) ||
94                                ((typoFlags & LE_CLIG_FEATURE_FLAG) && featureSetting == contextualLigaturesOnSelector) ||
95                                ((typoFlags & LE_HLIG_FEATURE_FLAG) && featureSetting == historicalLigaturesOnSelector) ||
96                                ((typoFlags & LE_LIGA_FEATURE_FLAG) && featureSetting == commonLigaturesOnSelector)) {
97                                flag &= disableFlags;
98                                flag |= enableFlags;
99                            }
100                        }
101                        break;
102                    case letterCaseType:
103                        if ((typoFlags & LE_SMCP_FEATURE_FLAG) && featureSetting == smallCapsSelector) {
104                            flag &= disableFlags;
105                            flag |= enableFlags;
106                        }
107                        break;
108                    case verticalSubstitutionType:
109                        break;
110                    case linguisticRearrangementType:
111                        break;
112                    case numberSpacingType:
113                        break;
114                    case smartSwashType:
115                        if ((typoFlags & LE_SWSH_FEATURE_FLAG) && (featureSetting ^ 0x1)){
116                            flag &= disableFlags;
117                            flag |= enableFlags;
118                        }
119                        break;
120                    case diacriticsType:
121                        break;
122                    case verticalPositionType:
123                        break;
124                    case fractionsType:
125                        if (((typoFlags & LE_FRAC_FEATURE_FLAG) && featureSetting == diagonalFractionsSelector) ||
126                            ((typoFlags & LE_AFRC_FEATURE_FLAG) && featureSetting == verticalFractionsSelector)) {
127                            flag &= disableFlags;
128                            flag |= enableFlags;
129                        } else {
130                            flag &= disableFlags;
131                        }
132                        break;
133                    case typographicExtrasType:
134                        if ((typoFlags & LE_ZERO_FEATURE_FLAG) && featureSetting == slashedZeroOnSelector) {
135                            flag &= disableFlags;
136                            flag |= enableFlags;
137                        }
138                        break;
139                    case mathematicalExtrasType:
140                        break;
141                    case ornamentSetsType:
142                        break;
143                    case characterAlternativesType:
144                        break;
145                    case designComplexityType:
146                        if (((typoFlags & LE_SS01_FEATURE_FLAG) && featureSetting == designLevel1Selector) ||
147                            ((typoFlags & LE_SS02_FEATURE_FLAG) && featureSetting == designLevel2Selector) ||
148                            ((typoFlags & LE_SS03_FEATURE_FLAG) && featureSetting == designLevel3Selector) ||
149                            ((typoFlags & LE_SS04_FEATURE_FLAG) && featureSetting == designLevel4Selector) ||
150                            ((typoFlags & LE_SS05_FEATURE_FLAG) && featureSetting == designLevel5Selector) ||
151                            ((typoFlags & LE_SS06_FEATURE_FLAG) && featureSetting == designLevel6Selector) ||
152                            ((typoFlags & LE_SS07_FEATURE_FLAG) && featureSetting == designLevel7Selector)) {
153
154                            flag &= disableFlags;
155                            flag |= enableFlags;
156                        }
157                        break;
158                    case styleOptionsType:
159                        break;
160                    case characterShapeType:
161                        break;
162                    case numberCaseType:
163                        break;
164                    case textSpacingType:
165                        break;
166                    case transliterationType:
167                        break;
168                    case annotationType:
169                        if ((typoFlags & LE_NALT_FEATURE_FLAG) && featureSetting == circleAnnotationSelector) {
170                            flag &= disableFlags;
171                            flag |= enableFlags;
172                        }
173                        break;
174                    case kanaSpacingType:
175                        break;
176                    case ideographicSpacingType:
177                        break;
178                    case rubyKanaType:
179                        if ((typoFlags & LE_RUBY_FEATURE_FLAG) && featureSetting == rubyKanaOnSelector) {
180                            flag &= disableFlags;
181                            flag |= enableFlags;
182                        }
183                        break;
184                    case cjkRomanSpacingType:
185                        break;
186                    default:
187                        break;
188                }
189            }
190        }
191
192        for (subtable = 0;  LE_SUCCESS(success) && subtable < nSubtables; subtable++) {
193            if(subtable>0)  {
194              le_uint32 length = SWAPL(subtableHeader->length);
195              if (length & 0x03) { // incorrect alignment for 32 bit tables
196                  success = LE_MEMORY_ALLOCATION_ERROR; // as good a choice as any
197                  return;
198              }
199              subtableHeader.addOffset(length, success); // Don't addOffset for the last entry.
200              if (LE_FAILURE(success)) break;
201            }
202            le_uint32 coverage = SWAPL(subtableHeader->coverage);
203            FeatureFlags subtableFeatures = SWAPL(subtableHeader->subtableFeatures);
204            // should check coverage more carefully...
205            if (((coverage & scfIgnoreVt2) || !(coverage & scfVertical2)) && (subtableFeatures & flag) != 0) {
206              subtableHeader->process(subtableHeader, glyphStorage, success);
207            }
208        }
209    }
210}
211
212void MorphSubtableHeader2::process(const LEReferenceTo<MorphSubtableHeader2> &base, LEGlyphStorage &glyphStorage, LEErrorCode &success) const
213{
214    SubtableProcessor2 *processor = NULL;
215
216    if (LE_FAILURE(success)) return;
217
218    switch (SWAPL(coverage) & scfTypeMask2)
219    {
220    case mstIndicRearrangement:
221        processor = new IndicRearrangementProcessor2(base, success);
222        break;
223
224    case mstContextualGlyphSubstitution:
225        processor = new ContextualGlyphSubstitutionProcessor2(base, success);
226        break;
227
228    case mstLigatureSubstitution:
229        processor = new LigatureSubstitutionProcessor2(base, success);
230        break;
231
232    case mstReservedUnused:
233        break;
234
235    case mstNonContextualGlyphSubstitution:
236        processor = NonContextualGlyphSubstitutionProcessor2::createInstance(base, success);
237        break;
238
239
240    case mstContextualGlyphInsertion:
241        processor = new ContextualGlyphInsertionProcessor2(base, success);
242        break;
243
244    default:
245        return;
246        break; /*NOTREACHED*/
247    }
248
249    if (processor != NULL) {
250      processor->process(glyphStorage, success);
251        delete processor;
252    } else {
253      if(LE_SUCCESS(success)) {
254        success = LE_MEMORY_ALLOCATION_ERROR; // because ptr is null and we didn't break out.
255      }
256    }
257}
258
259U_NAMESPACE_END
260