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