41 |
41 |
42 U_NAMESPACE_BEGIN |
42 U_NAMESPACE_BEGIN |
43 |
43 |
44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2) |
44 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2) |
45 |
45 |
46 ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2(const MorphSubtableHeader2 *morphSubtableHeader) |
46 ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2( |
47 : StateTableProcessor2(morphSubtableHeader) |
47 const LEReferenceTo<MorphSubtableHeader2> &morphSubtableHeader, LEErrorCode &success) |
|
48 : StateTableProcessor2(morphSubtableHeader, success) |
48 { |
49 { |
49 contextualGlyphHeader = (const ContextualGlyphInsertionHeader2 *) morphSubtableHeader; |
50 contextualGlyphHeader = LEReferenceTo<ContextualGlyphInsertionHeader2>(morphSubtableHeader, success); |
50 le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); |
51 if(LE_FAILURE(success) || !contextualGlyphHeader.isValid()) return; |
51 insertionTable = ((le_uint16 *) ((char *)&stateTableHeader->stHeader + insertionTableOffset)); |
52 le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset); |
52 entryTable = (const ContextualGlyphInsertionStateEntry2 *) ((char *) &stateTableHeader->stHeader + entryTableOffset); |
53 insertionTable = LEReferenceToArrayOf<le_uint16>(stHeader, success, insertionTableOffset, LE_UNBOUNDED_ARRAY); |
|
54 entryTable = LEReferenceToArrayOf<ContextualGlyphInsertionStateEntry2>(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY); |
53 } |
55 } |
54 |
56 |
55 ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2() |
57 ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2() |
56 { |
58 { |
57 } |
59 } |
59 void ContextualGlyphInsertionProcessor2::beginStateTable() |
61 void ContextualGlyphInsertionProcessor2::beginStateTable() |
60 { |
62 { |
61 markGlyph = 0; |
63 markGlyph = 0; |
62 } |
64 } |
63 |
65 |
64 le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex2 index) |
66 void ContextualGlyphInsertionProcessor2::doInsertion(LEGlyphStorage &glyphStorage, |
|
67 le_int16 atGlyph, |
|
68 le_int16 &index, |
|
69 le_int16 count, |
|
70 le_bool /* isKashidaLike */, |
|
71 le_bool isBefore, |
|
72 LEErrorCode &success) { |
|
73 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(atGlyph, count + 1, success); |
|
74 |
|
75 if(LE_FAILURE(success) || insertGlyphs==NULL) { |
|
76 return; |
|
77 } |
|
78 |
|
79 // Note: Kashida vs Split Vowel seems to only affect selection and highlighting. |
|
80 // We note the flag, but do not layout different. |
|
81 // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6mort.html |
|
82 |
|
83 le_int16 targetIndex = 0; |
|
84 if(isBefore) { |
|
85 // insert at beginning |
|
86 insertGlyphs[targetIndex++] = glyphStorage[atGlyph]; |
|
87 } else { |
|
88 // insert at end |
|
89 insertGlyphs[count] = glyphStorage[atGlyph]; |
|
90 } |
|
91 |
|
92 while(count--) { |
|
93 insertGlyphs[targetIndex++] = insertionTable.getObject(index++, success); |
|
94 } |
|
95 glyphStorage.applyInsertions(); |
|
96 } |
|
97 |
|
98 le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, |
|
99 EntryTableIndex2 index, LEErrorCode &success) |
65 { |
100 { |
66 const ContextualGlyphInsertionStateEntry2 *entry = &entryTable[index]; |
101 const ContextualGlyphInsertionStateEntry2 *entry = entryTable.getAlias(index, success); |
|
102 |
|
103 if(LE_FAILURE(success)) return 0; // TODO- which state? |
|
104 |
67 le_uint16 newState = SWAPW(entry->newStateIndex); |
105 le_uint16 newState = SWAPW(entry->newStateIndex); |
68 le_uint16 flags = SWAPW(entry->flags); |
106 le_uint16 flags = SWAPW(entry->flags); |
69 le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); |
107 |
70 le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); |
108 le_int16 markIndex = SWAPW(entry->markedInsertionListIndex); |
71 int i = 0; |
|
72 |
|
73 if (markIndex > 0) { |
109 if (markIndex > 0) { |
74 le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5; |
110 le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5; |
75 if (!(flags & cgiMarkedIsKashidaLike)) { |
111 le_bool isKashidaLike = (flags & cgiMarkedIsKashidaLike); |
76 // extra glyph(s) will be added directly before/after the specified marked glyph |
112 le_bool isBefore = (flags & cgiMarkInsertBefore); |
77 if (!(flags & cgiMarkInsertBefore)) { |
113 doInsertion(glyphStorage, markGlyph, markIndex, count, isKashidaLike, isBefore, success); |
78 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); |
|
79 for (i = 0; i < count; i++, markIndex++) { |
|
80 insertGlyphs[i] = insertionTable[markIndex]; |
|
81 } |
|
82 insertGlyphs[i] = glyphStorage[markGlyph]; |
|
83 glyphStorage.applyInsertions(); |
|
84 } else { |
|
85 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); |
|
86 insertGlyphs[0] = glyphStorage[markGlyph]; |
|
87 for (i = 1; i < count + 1; i++, markIndex++) { |
|
88 insertGlyphs[i] = insertionTable[markIndex]; |
|
89 } |
|
90 glyphStorage.applyInsertions(); |
|
91 } |
|
92 } else { |
|
93 // inserted as a split-vowel-like insertion |
|
94 // extra glyph(s) will be inserted some distance away from the marked glyph |
|
95 if (!(flags & cgiMarkInsertBefore)) { |
|
96 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); |
|
97 for (i = 0; i < count; i++, markIndex++) { |
|
98 insertGlyphs[i] = insertionTable[markIndex]; |
|
99 } |
|
100 insertGlyphs[i] = glyphStorage[markGlyph]; |
|
101 glyphStorage.applyInsertions(); |
|
102 } else { |
|
103 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(markGlyph, count + 1); |
|
104 insertGlyphs[0] = glyphStorage[markGlyph]; |
|
105 for (i = 1; i < count + 1; i++, markIndex++) { |
|
106 insertGlyphs[i] = insertionTable[markIndex]; |
|
107 } |
|
108 glyphStorage.applyInsertions(); |
|
109 } |
|
110 } |
|
111 } |
114 } |
112 |
115 |
|
116 le_int16 currIndex = SWAPW(entry->currentInsertionListIndex); |
113 if (currIndex > 0) { |
117 if (currIndex > 0) { |
114 le_int16 count = flags & cgiCurrentInsertCountMask; |
118 le_int16 count = flags & cgiCurrentInsertCountMask; |
115 if (!(flags & cgiCurrentIsKashidaLike)) { |
119 le_bool isKashidaLike = (flags & cgiCurrentIsKashidaLike); |
116 // extra glyph(s) will be added directly before/after the specified current glyph |
120 le_bool isBefore = (flags & cgiCurrentInsertBefore); |
117 if (!(flags & cgiCurrentInsertBefore)) { |
121 doInsertion(glyphStorage, currGlyph, currIndex, count, isKashidaLike, isBefore, success); |
118 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); |
|
119 for (i = 0; i < count; i++, currIndex++) { |
|
120 insertGlyphs[i] = insertionTable[currIndex]; |
|
121 } |
|
122 insertGlyphs[i] = glyphStorage[currGlyph]; |
|
123 glyphStorage.applyInsertions(); |
|
124 } else { |
|
125 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); |
|
126 insertGlyphs[0] = glyphStorage[currGlyph]; |
|
127 for (i = 1; i < count + 1; i++, currIndex++) { |
|
128 insertGlyphs[i] = insertionTable[currIndex]; |
|
129 } |
|
130 glyphStorage.applyInsertions(); |
|
131 } |
|
132 } else { |
|
133 // inserted as a split-vowel-like insertion |
|
134 // extra glyph(s) will be inserted some distance away from the current glyph |
|
135 if (!(flags & cgiCurrentInsertBefore)) { |
|
136 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); |
|
137 for (i = 0; i < count; i++, currIndex++) { |
|
138 insertGlyphs[i] = insertionTable[currIndex]; |
|
139 } |
|
140 insertGlyphs[i] = glyphStorage[currGlyph]; |
|
141 glyphStorage.applyInsertions(); |
|
142 } else { |
|
143 LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(currGlyph, count + 1); |
|
144 insertGlyphs[0] = glyphStorage[currGlyph]; |
|
145 for (i = 1; i < count + 1; i++, currIndex++) { |
|
146 insertGlyphs[i] = insertionTable[currIndex]; |
|
147 } |
|
148 glyphStorage.applyInsertions(); |
|
149 } |
|
150 } |
|
151 } |
122 } |
152 |
123 |
153 if (flags & cgiSetMark) { |
124 if (flags & cgiSetMark) { |
154 markGlyph = currGlyph; |
125 markGlyph = currGlyph; |
155 } |
126 } |