1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
/*
*
* (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
*
*/
#include "LETypes.h"
#include "OpenTypeTables.h"
#include "ArabicShaping.h"
#include "LEGlyphStorage.h"
U_NAMESPACE_BEGIN
enum {
_c_ = ArabicShaping::ST_NOSHAPE_DUAL,
_d_ = ArabicShaping::ST_DUAL,
_n_ = ArabicShaping::ST_NONE,
_r_ = ArabicShaping::ST_RIGHT,
_t_ = ArabicShaping::ST_TRANSPARENT,
_x_ = ArabicShaping::ST_NOSHAPE_NONE,
_A_ = ArabicShaping::ST_ALAPH,
_R_ = ArabicShaping::ST_DALATH_RISH
};
const ArabicShaping::ShapeType ArabicShaping::shapeTypes[] =
{
// Arabic block
_t_, _t_, _t_, _t_, _t_, _t_, _x_, _x_, _x_, _x_, _x_, _n_, _x_, _x_, _x_, _n_, // 0x610 - 0x61f
_x_, _n_, _r_, _r_, _r_, _r_, _d_, _r_, _d_, _r_, _d_, _d_, _d_, _d_, _d_, _r_, // 0x620 - 0x62f
_r_, _r_, _r_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _x_, _x_, _x_, _x_, _x_, // 0x630 - 0x63f
_c_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _r_, _d_, _d_, _t_, _t_, _t_, _t_, _t_, // 0x640 - 0x64f
_t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _x_, // 0x650 - 0x65f
_n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _d_, _d_, // 0x660 - 0x66f
_t_, _r_, _r_, _r_, _n_, _r_, _r_, _r_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x670 - 0x67f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, // 0x680 - 0x68f
_r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x690 - 0x69f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x6a0 - 0x6af
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x6b0 - 0x6bf
_r_, _d_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _r_, _d_, _r_, _d_, _r_, // 0x6c0 - 0x6cf
_d_, _d_, _r_, _r_, _n_, _r_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _x_, _t_, _t_, // 0x6d0 - 0x6df
_t_, _t_, _t_, _t_, _t_, _n_, _n_, _t_, _t_, _n_, _t_, _t_, _t_, _t_, _r_, _r_, // 0x6e0 - 0x6ef
_n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _d_, _d_, _d_, _n_, _n_, _d_, // 0x6f0 - 0x6ff
// Syriac
_n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _t_, // 0x700 - 0x70f
_A_, _t_, _d_, _d_, _d_, _R_, _R_, _r_, _r_, _r_, _d_, _d_, _d_, _d_, _r_, _d_, // 0x710 - 0x71f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _r_, _d_, _R_, _d_, _r_, _d_, _d_, _R_, // 0x720 - 0x72f
_t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, // 0x730 - 0x73f
_t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _t_, _x_, _x_, _r_, _d_, _d_, // 0x740 - 0x74f
// Arabic Supplement
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _r_, _r_, _r_, _d_, _d_, _d_, _d_, // 0x750 - 0x75f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _r_, _r_, _d_, _x_, _x_, // 0x760 - 0x76f
_x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_, _x_ // 0x770 - 0x77f
};
const ArabicShaping::ShapeType ArabicShaping::mongolianTypes[] =
{
_n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _t_, _t_, _t_, _t_, _n_, // 0x1800 - 0x180f
_n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, // 0x1810 - 0x181f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1820 - 0x182f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1830 - 0x183f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1840 - 0x184f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1850 - 0x185f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1860 - 0x186f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, _n_, // 0x1870 - 0x187f
_n_, _n_, _n_, _n_, _n_, _n_, _n_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1880 - 0x188f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, // 0x1890 - 0x189f
_d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _d_, _t_, _n_, _n_, _n_, _n_, _n_, _n_ // 0x18a0 - 0x18af
};
/*
shaping array holds types for Arabic/Syriac chars between 0610 and 077f;
mongolian array holds types for Mongolian chars between 1800 and 18af;
other values are either unshaped, or transparent if a mark or format
code, except for format codes 200c (zero-width non-joiner) and 200d
(dual-width joiner) which are both unshaped and non_joining or
dual-joining, respectively.
*/
ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c)
{
if (c >= 0x0300 && c <= 0x206f) {
if (/*c >= 0x0300 &&*/ c <= 0x036f) { // Combining Marks
return ST_TRANSPARENT;
} else if (c >= 0x0610 && c <= 0x077f) { // Arabic/Syriac/Arabic Supplement
return shapeTypes[c - 0x0610];
} else if (c >= 0x1800 && c <= 0x18af) { // Mongolian
return mongolianTypes[c - 0x1800];
} else if (c == 0x200c) { // ZWNJ
return ST_NOSHAPE_NONE;
} else if (c == 0x200d) { // ZWJ
return ST_NOSHAPE_DUAL;
} else if (c >= 0x202a && c <= 0x202e) { // LRE - RLO
return ST_TRANSPARENT;
} else if (c >= 0x206a /*&& c <= 0x206f*/) { // Inhibit Symmetric Swapping - Nominal Digit Shapes
return ST_TRANSPARENT;
}
}
return ST_NOSHAPE_NONE;
}
static const LETag isolFeatureTag = LE_ISOL_FEATURE_TAG;
static const LETag initFeatureTag = LE_INIT_FEATURE_TAG;
static const LETag mediFeatureTag = LE_MEDI_FEATURE_TAG;
static const LETag finaFeatureTag = LE_FINA_FEATURE_TAG;
static const LETag ligaFeatureTag = LE_LIGA_FEATURE_TAG;
static const LETag msetFeatureTag = LE_MSET_FEATURE_TAG;
static const LETag markFeatureTag = LE_MARK_FEATURE_TAG;
static const LETag ccmpFeatureTag = LE_CCMP_FEATURE_TAG;
static const LETag rligFeatureTag = LE_RLIG_FEATURE_TAG;
static const LETag caltFeatureTag = LE_CALT_FEATURE_TAG;
static const LETag dligFeatureTag = LE_DLIG_FEATURE_TAG;
static const LETag cswhFeatureTag = LE_CSWH_FEATURE_TAG;
static const LETag cursFeatureTag = LE_CURS_FEATURE_TAG;
static const LETag kernFeatureTag = LE_KERN_FEATURE_TAG;
static const LETag mkmkFeatureTag = LE_MKMK_FEATURE_TAG;
static const LETag med2FeatureTag = LE_MED2_FEATURE_TAG;
static const LETag fin2FeatureTag = LE_FIN2_FEATURE_TAG;
static const LETag fin3FeatureTag = LE_FIN3_FEATURE_TAG;
static const LETag emptyTag = 0x00000000; // ''
static const LETag featureOrder[] =
{
ccmpFeatureTag, isolFeatureTag, finaFeatureTag, fin2FeatureTag, fin3FeatureTag, mediFeatureTag,
med2FeatureTag, initFeatureTag, rligFeatureTag, caltFeatureTag, ligaFeatureTag, dligFeatureTag,
cswhFeatureTag, msetFeatureTag, cursFeatureTag, kernFeatureTag, markFeatureTag, mkmkFeatureTag,
emptyTag
};
const LETag ArabicShaping::tagArray[] =
{
isolFeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
finaFeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
initFeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
mediFeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
fin2FeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
fin3FeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
med2FeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag,
med2FeatureTag, ligaFeatureTag, msetFeatureTag, markFeatureTag, ccmpFeatureTag, rligFeatureTag,
caltFeatureTag, dligFeatureTag, cswhFeatureTag, cursFeatureTag, kernFeatureTag, mkmkFeatureTag, emptyTag
// this entry repeated so that both fin2 and fin3 map to med2 via a +2 offset
};
#define TAGS_PER_GLYPH ((sizeof ArabicShaping::tagArray / sizeof ArabicShaping::tagArray[0]) / 8)
const LETag *ArabicShaping::getFeatureOrder()
{
return featureOrder;
}
void ArabicShaping::adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage)
{
LEErrorCode success = LE_NO_ERROR;
const LETag *glyphTags = (const LETag *) glyphStorage.getAuxData(outIndex, success);
glyphStorage.setAuxData(outIndex, (void *) &glyphTags[TAGS_PER_GLYPH * shapeOffset], success);
}
void ArabicShaping::shape(const LEUnicode *chars, le_int32 offset, le_int32 charCount, le_int32 charMax,
le_bool rightToLeft, LEGlyphStorage &glyphStorage)
{
// iterate in logical order, store tags in visible order
//
// the effective right char is the most recently encountered
// non-transparent char
//
// four boolean states:
// the effective right char shapes
// the effective right char causes left shaping
// the current char shapes
// the current char causes right shaping
//
// if both cause shaping, then
// shaper.shape(errout, 2) (isolate to initial, or final to medial)
// shaper.shape(out, 1) (isolate to final)
// special cases for Syriac ALAPH:
// final ALAPH is fin2 when effective right char shapes but does not cause left shaping, and is not DALATH/RISH
// final ALAPH is fin3 when effective right char is DALATH/RISH
// medial ALAPH is med2 when effective right char shapes but does not cause left shaping
// using one of:
// shaper.shape(out, 4) (isolate to fin2)
// shaper.shape(out, 5) (isolate to fin3)
ShapeType rightType = ST_NOSHAPE_NONE, leftType = ST_NOSHAPE_NONE;
LEErrorCode success = LE_NO_ERROR;
le_int32 i;
for (i = offset - 1; i >= 0; i -= 1) {
rightType = getShapeType(chars[i]);
if (rightType != ST_TRANSPARENT) {
break;
}
}
for (i = offset + charCount; i < charMax; i += 1) {
leftType = getShapeType(chars[i]);
if (leftType != ST_TRANSPARENT) {
break;
}
}
// erout is effective right logical index
le_int32 erout = -1;
le_bool rightShapes = FALSE;
le_bool rightCauses = (rightType & MASK_SHAPE_LEFT) != 0;
le_int32 in, e, out = 0, dir = 1;
if (rightToLeft) {
out = charCount - 1;
erout = charCount;
dir = -1;
}
for (in = offset, e = offset + charCount; in < e; in += 1, out += dir) {
LEUnicode c = chars[in];
ShapeType t = getShapeType(c);
glyphStorage.setAuxData(out, (void *) tagArray, success);
if ((t & MASK_TRANSPARENT) != 0) {
continue;
}
le_bool curShapes = (t & MASK_NOSHAPE) == 0;
le_bool curCauses = (t & MASK_SHAPE_RIGHT) != 0;
if (rightCauses && curCauses) {
if (rightShapes) {
adjustTags(erout, 2, glyphStorage);
}
if (curShapes) {
adjustTags(out, 1, glyphStorage);
}
} else if (t == ST_ALAPH) {
if (rightType == ST_DALATH_RISH) {
adjustTags(out, 5, glyphStorage);
} else if (rightShapes && !rightCauses) {
adjustTags(out, 4, glyphStorage);
}
}
rightShapes = curShapes;
rightCauses = (t & MASK_SHAPE_LEFT) != 0;
rightType = t; // remember this; might need to know if it was DALATH/RISH
erout = out;
}
if (rightShapes && rightCauses && (leftType & MASK_SHAPE_RIGHT) != 0) {
adjustTags(erout, 2, glyphStorage);
}
}
U_NAMESPACE_END
|