summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp
blob: fbd77ef5b3bb7f90dea01bca2f37cb87d0e2b83c (plain)
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/****************************************************************************\
 Part of the XeTeX typesetting system
 copyright (c) 1994-2008 by SIL International
 copyright (c) 2009 by Jonathan Kew

 Written by Jonathan Kew

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of the copyright holders
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization from the copyright holders.
\****************************************************************************/

#include "XeTeXOTLayoutEngine.h"

/****************************************************************************\
class XeTeXHanLayoutEngine
  moved from XeTeXOTLayoutEngine.h to here in order not to include it into
  XeTeXLayoutInterface.cpp.
\****************************************************************************/
class XeTeXHanLayoutEngine : public XeTeXOTLayoutEngine
{
public:
    XeTeXHanLayoutEngine(const XeTeXFontInst *fontInstance, LETag scriptTag, LETag languageTag,
                            const GlyphSubstitutionTableHeader *gsubTable,
                            const GlyphPositioningTableHeader* gposTable,
							const LETag* addFeatures, const le_int32* addParams,
							const LETag* removeFeatures
#if U_ICU_VERSION_CODE >= 42
				, LEErrorCode &success
#endif
			);

    virtual ~XeTeXHanLayoutEngine();

    virtual UClassID getDynamicClassID() const;
    static UClassID getStaticClassID();
};

#include "layout/ArabicLayoutEngine.h"
#include "layout/IndicLayoutEngine.h"
#include "layout/TibetanLayoutEngine.h"
#include "layout/ThaiLayoutEngine.h"
#include "layout/KhmerLayoutEngine.h"

#include "layout/LEScripts.h"
#include "layout/LELanguages.h"

const LETag emptyTag = 0x00000000;

static le_int32 getScriptCode(LETag scriptTag)
{
	for (le_int32 i = 0; i < scriptCodeCount; ++i)
		if (OpenTypeLayoutEngine::getScriptTag(i) == scriptTag)
			return i;
	return -1;
}

static le_int32 getLanguageCode(LETag languageTag)
{
	for (le_int32 i = 0; i < languageCodeCount; ++i)
		if (OpenTypeLayoutEngine::getLangSysTag(i) == languageTag)
			return i;
	return -1;
}

/*
 * XeTeXOTLayoutEngine
 */

UOBJECT_DEFINE_RTTI_IMPLEMENTATION(XeTeXOTLayoutEngine)

LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory
				(const XeTeXFontInst* fontInstance,
					LETag scriptTag, LETag languageTag,
					const LETag* addFeatures, const le_int32* addParams,
					const LETag* removeFeatures,
					LEErrorCode &success)
{
    static le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
    static le_uint32 gposTableTag = LE_GPOS_TABLE_TAG;

    if (LE_FAILURE(success))
        return NULL;

    const GlyphSubstitutionTableHeader* gsubTable = (const GlyphSubstitutionTableHeader*)fontInstance->getFontTable(gsubTableTag);
    const GlyphPositioningTableHeader* gposTable = (const GlyphPositioningTableHeader*)fontInstance->getFontTable(gposTableTag);
    LayoutEngine *result = NULL;
	
	le_uint32   scriptCode = getScriptCode(scriptTag);
	le_uint32   languageCode = getLanguageCode(languageTag);

	le_int32	typoFlags = 3;

    if ((gsubTable != NULL && gsubTable->coversScript(scriptTag))
    	|| (gposTable != NULL && gposTable->coversScript(scriptTag))) {
        switch (scriptCode) {
        case bengScriptCode:
        case devaScriptCode:
        case gujrScriptCode:
        case kndaScriptCode:
        case mlymScriptCode:
        case oryaScriptCode:
        case guruScriptCode:
        case tamlScriptCode:
        case teluScriptCode:
        case sinhScriptCode:
//            result = new XeTeXIndicLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, removeFeatures);
            result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags,
#if U_ICU_VERSION_CODE >= 42
                                                   FALSE,
#endif
                                                   gsubTable XeTeX_success);
            break;

        case arabScriptCode:
        case syrcScriptCode:
        case mongScriptCode:
//            result = new XeTeXArabicLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, removeFeatures);
            result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable XeTeX_success);
            break;

        case bopoScriptCode:
        case haniScriptCode:
        case hangScriptCode:
        case hiraScriptCode:
        case kanaScriptCode:
        case hrktScriptCode:
            result = new XeTeXHanLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, gposTable, addFeatures, addParams, removeFeatures XeTeX_success);
            break;

        case tibtScriptCode:
            result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable XeTeX_success);
            break;

        case khmrScriptCode:
            result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable XeTeX_success);
            break;

        default:
            result = new XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, gposTable, addFeatures, addParams, removeFeatures XeTeX_success);
            break;
        }
    }
	else {
		switch (scriptCode) {
		case bengScriptCode:
		case devaScriptCode:
		case gujrScriptCode:
		case kndaScriptCode:
		case mlymScriptCode:
		case oryaScriptCode:
		case guruScriptCode:
		case tamlScriptCode:
		case teluScriptCode:
		case sinhScriptCode:
			result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags XeTeX_success);
			break;

		case arabScriptCode:
//		case hebrScriptCode:
			result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags XeTeX_success);
			break;

		case thaiScriptCode:
			result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags XeTeX_success);
			break;

		default:
			result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags XeTeX_success);
			break;
		}
    }

#if U_ICU_VERSION_CODE >= 42
    if (LE_FAILURE(success))
        return NULL;
#else
    if (result == NULL)
        success = LE_MEMORY_ALLOCATION_ERROR;
#endif

    return result;
}

XeTeXOTLayoutEngine::XeTeXOTLayoutEngine(
	const LEFontInstance* fontInstance, LETag scriptTag, LETag languageTag,
	const GlyphSubstitutionTableHeader* gsubTable, const GlyphPositioningTableHeader* gposTable,
	const LETag* addFeatures, const le_int32* addParams, const LETag* removeFeatures
#if U_ICU_VERSION_CODE >= 42
				, LEErrorCode &success
#endif
			)
		: OpenTypeLayoutEngine(fontInstance, getScriptCode(scriptTag), getLanguageCode(languageTag), 3, gsubTable XeTeX_success)
{
	fDefaultFeatureMap = fFeatureMap;
	
	// check the result of setScriptAndLanguageTags(), in case they were unknown to ICU
	if (fScriptTag != scriptTag || fLangSysTag != languageTag) {
		fScriptTag = scriptTag;
		fLangSysTag = languageTag;
	
		// reset the GPOS if the tags changed
		fGPOSTable = NULL;
		if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) {
			fGPOSTable = gposTable;
		}
	}

	adjustFeatures(addFeatures, addParams, removeFeatures);
}

XeTeXOTLayoutEngine::~XeTeXOTLayoutEngine()
{
	if (fFeatureMap != NULL && fFeatureMap != fDefaultFeatureMap)
		LE_DELETE_ARRAY(fFeatureMap);
	if (fFeatureParamList != NULL)
		LE_DELETE_ARRAY(fFeatureParamList);
}

void XeTeXOTLayoutEngine::adjustFeatures(const LETag* addTags, const le_int32* addParams, const LETag* removeTags)
{
	// bail out if nothing was requested!
	if ((addTags == NULL || *addTags == emptyTag) && (removeTags == NULL || *removeTags == emptyTag))
		return;

	// figure out total tag count: initial set - removed tags + added tags omitting duplicates
	le_int32	totalCount = 0;
	for (le_int32 i = 0; i < fFeatureMapCount; ++i) {
		// skip any that are disabled by the mask
		if ((fFeatureMask & fFeatureMap[i].mask) != 0) {
			bool	remove = false;
			for (const LETag* r = removeTags; r != NULL && *r != emptyTag; ++r)
				if (*r == fFeatureMap[i].tag) {
					remove = true;
					break;
				}
			if (!remove)
				++totalCount;
		}
	}
	for (const LETag* a = addTags; a != NULL && *a != emptyTag; ++a) {
		// before counting an add tag, check original map, and check for duplicates in list
		bool	add = true;
		for (le_int32 i = 0; i < fFeatureMapCount; ++i)
			if (*a == fFeatureMap[i].tag) {
				if ((fFeatureMask & fFeatureMap[i].mask) != 0)
					add = false;
				break;
			}
		if (add) {
			for (const LETag* t = addTags; t != a; ++t)
				if (*a == *t) {
					add = false;
					break;
				}
		}
		if (add)
			++totalCount;
	}
	
	if (totalCount > 32)
		fprintf(stderr, "\n*** feature count exceeds mask size; some features will be ignored\n");

	// allocate new map
	FeatureMap* newFeatureMap = LE_NEW_ARRAY(FeatureMap, totalCount);
	le_int32	newFeatureCount = 0;
	le_int32*	newParamList = (addParams == NULL) ? NULL : LE_NEW_ARRAY(le_int32, totalCount);
	
	// copy the features into the map and assign mask bits
	FeatureMask	newFeatureMask = 0;
	FeatureMask	maskBit = 0x80000000UL;
	for (le_int32 i = 0; i < fFeatureMapCount; ++i) {
		bool	remove = false;
		if ((fFeatureMask & fFeatureMap[i].mask) == 0)
			remove = true;
		else
			for (const LETag* r = removeTags; r != NULL && *r != emptyTag; ++r)
				if (*r == fFeatureMap[i].tag) {
					remove = true;
					break;
				}
		if (!remove) {
			newFeatureMap[newFeatureCount].tag = fFeatureMap[i].tag;
			newFeatureMap[newFeatureCount].mask = maskBit;
			if (newParamList != NULL)
				newParamList[newFeatureCount] = 0;
			++newFeatureCount;
			newFeatureMask |= maskBit;
			maskBit >>= 1;
		}
	}
	const le_int32* param = addParams;
	for (const LETag* a = addTags; a != NULL && *a != emptyTag; ++a) {
		bool	add = true;
		for (le_int32 i = 0; i < fFeatureMapCount; ++i)
			if (*a == fFeatureMap[i].tag) {
				if ((fFeatureMask & fFeatureMap[i].mask) != 0)
					add = false;
				break;
			}
		if (add) {
			for (const LETag* t = addTags; t != a; ++t)
				if (*a == *t) {
					add = false;
					break;
				}
		}
		if (add) {
			newFeatureMap[newFeatureCount].tag = *a;
			newFeatureMap[newFeatureCount].mask = maskBit;
			if (newParamList != NULL)
				newParamList[newFeatureCount] = *param++;
			++newFeatureCount;
			newFeatureMask |= maskBit;
			maskBit >>= 1;
		}
	}

	fFeatureMask = newFeatureMask;
	fFeatureMap = newFeatureMap;
	fFeatureMapCount = newFeatureCount;
	fFeatureParamList = newParamList;
}


/*
 * XeTeXHanLayoutEngine
 */

UOBJECT_DEFINE_RTTI_IMPLEMENTATION(XeTeXHanLayoutEngine)

static const LETag loclFeatureTag = LE_LOCL_FEATURE_TAG;
static const LETag smplFeatureTag = LE_SMPL_FEATURE_TAG;
static const LETag tradFeatureTag = LE_TRAD_FEATURE_TAG;
static const LETag vertFeatureTag = LE_VERT_FEATURE_TAG;
static const LETag vrt2FeatureTag = LE_VRT2_FEATURE_TAG;

#define loclFeatureMask 0x80000000UL
#define smplFeatureMask 0x40000000UL
#define tradFeatureMask 0x20000000UL
#define vertFeatureMask 0x10000000UL
#define vrt2FeatureMask 0x08000000UL

static const FeatureMap featureMap[] = {
    {loclFeatureTag, loclFeatureMask},
    {smplFeatureTag, smplFeatureMask},
    {tradFeatureTag, tradFeatureMask},
    {vertFeatureTag, vertFeatureMask},
    {vrt2FeatureTag, vrt2FeatureMask},
};
static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap);

#define HORIZ_FEATURES (loclFeatureMask)
#define VERT_FEATURES  (loclFeatureMask|vertFeatureMask|vrt2FeatureMask)

XeTeXHanLayoutEngine::XeTeXHanLayoutEngine(const XeTeXFontInst *fontInstance, LETag scriptTag, LETag languageTag,
                            const GlyphSubstitutionTableHeader *gsubTable, const GlyphPositioningTableHeader *gposTable,
							const LETag *addFeatures, const le_int32* addParams,
							const LETag *removeFeatures
#if U_ICU_VERSION_CODE >= 42
				, LEErrorCode &success
#endif
			)
	: XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, gposTable, NULL, NULL, NULL XeTeX_success)
{
	// reset the feature map and default features
	fFeatureMap = featureMap;
	fDefaultFeatureMap = fFeatureMap;
	fFeatureMapCount = featureMapCount;

	fFeatureMask = fontInstance->getLayoutDirVertical() ? VERT_FEATURES : HORIZ_FEATURES;
	
	// then apply any adjustments
	adjustFeatures(addFeatures, addParams, removeFeatures);
}

XeTeXHanLayoutEngine::~XeTeXHanLayoutEngine()
{
}