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 *
28 * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
29 *
30 */
31
32#include "LETypes.h"
33#include "MorphTables.h"
34#include "StateTables.h"
35#include "MorphStateTables.h"
36#include "SubtableProcessor.h"
37#include "StateTableProcessor.h"
38#include "IndicRearrangementProcessor.h"
39#include "LEGlyphStorage.h"
40#include "LESwaps.h"
41
42U_NAMESPACE_BEGIN
43
44UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IndicRearrangementProcessor)
45
46  IndicRearrangementProcessor::IndicRearrangementProcessor(const LEReferenceTo<MorphSubtableHeader> &morphSubtableHeader, LEErrorCode &success)
47  : StateTableProcessor(morphSubtableHeader, success),
48  indicRearrangementSubtableHeader(morphSubtableHeader, success),
49  entryTable(stateTableHeader, success, (const IndicRearrangementStateEntry*)(&stateTableHeader->stHeader),
50             entryTableOffset, LE_UNBOUNDED_ARRAY),
51  int16Table(stateTableHeader, success, (const le_int16*)entryTable.getAlias(), 0, LE_UNBOUNDED_ARRAY)
52
53{
54}
55
56IndicRearrangementProcessor::~IndicRearrangementProcessor()
57{
58}
59
60void IndicRearrangementProcessor::beginStateTable()
61{
62    firstGlyph = 0;
63    lastGlyph = 0;
64}
65
66ByteOffset IndicRearrangementProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index, LEErrorCode &success)
67{
68    const IndicRearrangementStateEntry *entry = entryTable.getAlias(index, success);
69    if (LE_FAILURE(success)) return 0;
70    ByteOffset newState = SWAPW(entry->newStateOffset);
71    IndicRearrangementFlags flags = (IndicRearrangementFlags) SWAPW(entry->flags);
72
73    if (currGlyph < 0 || currGlyph >= glyphStorage.getGlyphCount()) {
74       success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
75       return 0;
76    }
77
78    if (flags & irfMarkFirst) {
79        firstGlyph = currGlyph;
80    }
81
82    if (flags & irfMarkLast) {
83        lastGlyph = currGlyph;
84    }
85
86    doRearrangementAction(glyphStorage, (IndicRearrangementVerb) (flags & irfVerbMask), success);
87
88    if (!(flags & irfDontAdvance)) {
89        // XXX: Should handle reverse too...
90        currGlyph += 1;
91    }
92
93    return newState;
94}
95
96void IndicRearrangementProcessor::endStateTable()
97{
98}
99
100void IndicRearrangementProcessor::doRearrangementAction(LEGlyphStorage &glyphStorage, IndicRearrangementVerb verb, LEErrorCode &success) const
101{
102    LEGlyphID a, b, c, d;
103    le_int32 ia, ib, ic, id, ix, x;
104
105    if (LE_FAILURE(success)) return;
106
107    if (verb == irvNoAction) {
108        return;
109    }
110    if (firstGlyph > lastGlyph) {
111        success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
112        return;
113    }
114
115    switch(verb)
116    {
117    case irvxA:
118        if (firstGlyph == lastGlyph) break;
119        if (firstGlyph + 1 < firstGlyph) {
120            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
121            break;
122        }
123        a = glyphStorage[firstGlyph];
124        ia = glyphStorage.getCharIndex(firstGlyph, success);
125        x = firstGlyph + 1;
126
127        while (x <= lastGlyph) {
128            glyphStorage[x - 1] = glyphStorage[x];
129            ix = glyphStorage.getCharIndex(x, success);
130            glyphStorage.setCharIndex(x - 1, ix, success);
131            x += 1;
132        }
133
134        glyphStorage[lastGlyph] = a;
135        glyphStorage.setCharIndex(lastGlyph, ia, success);
136        break;
137
138    case irvDx:
139        if (firstGlyph == lastGlyph) break;
140        if (lastGlyph - 1 > lastGlyph) {
141            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
142            break;
143        }
144        d = glyphStorage[lastGlyph];
145        id = glyphStorage.getCharIndex(lastGlyph, success);
146        x = lastGlyph - 1;
147
148        while (x >= firstGlyph) {
149            glyphStorage[x + 1] = glyphStorage[x];
150            ix = glyphStorage.getCharIndex(x, success);
151            glyphStorage.setCharIndex(x + 1, ix, success);
152            x -= 1;
153        }
154
155        glyphStorage[firstGlyph] = d;
156        glyphStorage.setCharIndex(firstGlyph, id, success);
157        break;
158
159    case irvDxA:
160        a = glyphStorage[firstGlyph];
161        ia = glyphStorage.getCharIndex(firstGlyph, success);
162        id = glyphStorage.getCharIndex(lastGlyph,  success);
163
164        glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
165        glyphStorage[lastGlyph] = a;
166
167        glyphStorage.setCharIndex(firstGlyph, id, success);
168        glyphStorage.setCharIndex(lastGlyph,  ia, success);
169        break;
170
171    case irvxAB:
172        if ((firstGlyph + 2 < firstGlyph) ||
173            (lastGlyph - firstGlyph < 1)) { // difference == 1 is a no-op, < 1 is an error.
174            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
175            break;
176        }
177        a = glyphStorage[firstGlyph];
178        b = glyphStorage[firstGlyph + 1];
179        ia = glyphStorage.getCharIndex(firstGlyph, success);
180        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
181        x = firstGlyph + 2;
182
183        while (x <= lastGlyph) {
184            glyphStorage[x - 2] = glyphStorage[x];
185            ix = glyphStorage.getCharIndex(x, success);
186            glyphStorage.setCharIndex(x - 2, ix, success);
187            x += 1;
188        }
189
190        glyphStorage[lastGlyph - 1] = a;
191        glyphStorage[lastGlyph] = b;
192
193        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
194        glyphStorage.setCharIndex(lastGlyph, ib, success);
195        break;
196
197    case irvxBA:
198        if ((firstGlyph + 2 < firstGlyph) ||
199            (lastGlyph - firstGlyph < 1)) {
200            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
201            break;
202        }
203        a = glyphStorage[firstGlyph];
204        b = glyphStorage[firstGlyph + 1];
205        ia = glyphStorage.getCharIndex(firstGlyph, success);
206        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
207        x = firstGlyph + 2;
208
209        while (x <= lastGlyph) {
210            glyphStorage[x - 2] = glyphStorage[x];
211            ix = glyphStorage.getCharIndex(x, success);
212            glyphStorage.setCharIndex(x - 2, ix, success);
213            x += 1;
214        }
215
216        glyphStorage[lastGlyph - 1] = b;
217        glyphStorage[lastGlyph] = a;
218
219        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
220        glyphStorage.setCharIndex(lastGlyph, ia, success);
221        break;
222
223    case irvCDx:
224        if ((lastGlyph - 2 > lastGlyph) ||
225            (lastGlyph - firstGlyph < 1)) {
226            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
227            break;
228        }
229        c = glyphStorage[lastGlyph - 1];
230        d = glyphStorage[lastGlyph];
231        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
232        id = glyphStorage.getCharIndex(lastGlyph, success);
233        x = lastGlyph - 2;
234
235        while (x >= firstGlyph) {
236            glyphStorage[x + 2] = glyphStorage[x];
237            ix = glyphStorage.getCharIndex(x, success);
238            glyphStorage.setCharIndex(x + 2, ix, success);
239            x -= 1;
240        }
241
242        glyphStorage[firstGlyph] = c;
243        glyphStorage[firstGlyph + 1] = d;
244
245        glyphStorage.setCharIndex(firstGlyph, ic, success);
246        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
247        break;
248
249    case irvDCx:
250        if ((lastGlyph - 2 > lastGlyph) ||
251            (lastGlyph - firstGlyph < 1)) {
252            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
253            break;
254        }
255        c = glyphStorage[lastGlyph - 1];
256        d = glyphStorage[lastGlyph];
257        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
258        id = glyphStorage.getCharIndex(lastGlyph, success);
259        x = lastGlyph - 2;
260
261        while (x >= firstGlyph) {
262            glyphStorage[x + 2] = glyphStorage[x];
263            ix = glyphStorage.getCharIndex(x, success);
264            glyphStorage.setCharIndex(x + 2, ix, success);
265            x -= 1;
266        }
267
268        glyphStorage[firstGlyph] = d;
269        glyphStorage[firstGlyph + 1] = c;
270
271        glyphStorage.setCharIndex(firstGlyph, id, success);
272        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
273        break;
274
275    case irvCDxA:
276        if ((lastGlyph - 2 > lastGlyph) ||
277            (lastGlyph - firstGlyph < 2)) {
278            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
279            break;
280        }
281        a = glyphStorage[firstGlyph];
282        c = glyphStorage[lastGlyph - 1];
283        d = glyphStorage[lastGlyph];
284        ia = glyphStorage.getCharIndex(firstGlyph, success);
285        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
286        id = glyphStorage.getCharIndex(lastGlyph, success);
287        x = lastGlyph - 2;
288
289        while (x > firstGlyph) {
290            glyphStorage[x + 1] = glyphStorage[x];
291            ix = glyphStorage.getCharIndex(x, success);
292            glyphStorage.setCharIndex(x + 1, ix, success);
293            x -= 1;
294        }
295
296        glyphStorage[firstGlyph] = c;
297        glyphStorage[firstGlyph + 1] = d;
298        glyphStorage[lastGlyph] = a;
299
300        glyphStorage.setCharIndex(firstGlyph, ic, success);
301        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
302        glyphStorage.setCharIndex(lastGlyph, ia, success);
303        break;
304
305    case irvDCxA:
306        if ((lastGlyph - 2 > lastGlyph) ||
307            (lastGlyph - firstGlyph < 2)) {
308            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
309            break;
310        }
311        a = glyphStorage[firstGlyph];
312        c = glyphStorage[lastGlyph - 1];
313        d = glyphStorage[lastGlyph];
314        ia = glyphStorage.getCharIndex(firstGlyph, success);
315        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
316        id = glyphStorage.getCharIndex(lastGlyph, success);
317        x = lastGlyph - 2;
318
319        while (x > firstGlyph) {
320            glyphStorage[x + 1] = glyphStorage[x];
321            ix = glyphStorage.getCharIndex(x, success);
322            glyphStorage.setCharIndex(x + 1, ix, success);
323            x -= 1;
324        }
325
326        glyphStorage[firstGlyph] = d;
327        glyphStorage[firstGlyph + 1] = c;
328        glyphStorage[lastGlyph] = a;
329
330        glyphStorage.setCharIndex(firstGlyph, id, success);
331        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
332        glyphStorage.setCharIndex(lastGlyph, ia, success);
333        break;
334
335    case irvDxAB:
336        if ((firstGlyph + 2 < firstGlyph) ||
337            (lastGlyph - firstGlyph < 2)) {
338            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
339            break;
340        }
341        a = glyphStorage[firstGlyph];
342        b = glyphStorage[firstGlyph + 1];
343        d = glyphStorage[lastGlyph];
344        ia = glyphStorage.getCharIndex(firstGlyph, success);
345        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
346        id = glyphStorage.getCharIndex(lastGlyph, success);
347        x = firstGlyph + 2;
348
349        while (x < lastGlyph) {
350            glyphStorage[x - 2] = glyphStorage[x];
351            ix = glyphStorage.getCharIndex(x, success);
352            glyphStorage.setCharIndex(x - 2, ix, success);
353            x += 1;
354        }
355
356        glyphStorage[firstGlyph] = d;
357        glyphStorage[lastGlyph - 1] = a;
358        glyphStorage[lastGlyph] = b;
359
360        glyphStorage.setCharIndex(firstGlyph, id, success);
361        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
362        glyphStorage.setCharIndex(lastGlyph, ib, success);
363        break;
364
365    case irvDxBA:
366        if ((firstGlyph + 2 < firstGlyph) ||
367            (lastGlyph - firstGlyph < 2)) {
368            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
369            break;
370        }
371        a = glyphStorage[firstGlyph];
372        b = glyphStorage[firstGlyph + 1];
373        d = glyphStorage[lastGlyph];
374        ia = glyphStorage.getCharIndex(firstGlyph, success);
375        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
376        id = glyphStorage.getCharIndex(lastGlyph, success);
377        x = firstGlyph + 2;
378
379        while (x < lastGlyph) {
380            glyphStorage[x - 2] = glyphStorage[x];
381            ix = glyphStorage.getCharIndex(x, success);
382            glyphStorage.setCharIndex(x - 2, ix, success);
383            x += 1;
384        }
385
386        glyphStorage[firstGlyph] = d;
387        glyphStorage[lastGlyph - 1] = b;
388        glyphStorage[lastGlyph] = a;
389
390        glyphStorage.setCharIndex(firstGlyph, id, success);
391        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
392        glyphStorage.setCharIndex(lastGlyph, ia, success);
393        break;
394
395    case irvCDxAB:
396        if (lastGlyph - firstGlyph < 3) {
397            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
398            break;
399        }
400        a = glyphStorage[firstGlyph];
401        b = glyphStorage[firstGlyph + 1];
402
403        glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1];
404        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph];
405
406        glyphStorage[lastGlyph - 1] = a;
407        glyphStorage[lastGlyph] = b;
408
409        ia = glyphStorage.getCharIndex(firstGlyph, success);
410        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
411        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
412        id = glyphStorage.getCharIndex(lastGlyph, success);
413
414        glyphStorage.setCharIndex(firstGlyph, ic, success);
415        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
416
417        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
418        glyphStorage.setCharIndex(lastGlyph, ib, success);
419        break;
420
421    case irvCDxBA:
422        if (lastGlyph - firstGlyph < 3) {
423            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
424            break;
425        }
426        a = glyphStorage[firstGlyph];
427        b = glyphStorage[firstGlyph + 1];
428
429        glyphStorage[firstGlyph] = glyphStorage[lastGlyph - 1];
430        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph];
431
432        glyphStorage[lastGlyph - 1] = b;
433        glyphStorage[lastGlyph] = a;
434
435        ia = glyphStorage.getCharIndex(firstGlyph, success);
436        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
437        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
438        id = glyphStorage.getCharIndex(lastGlyph, success);
439
440        glyphStorage.setCharIndex(firstGlyph, ic, success);
441        glyphStorage.setCharIndex(firstGlyph + 1, id, success);
442
443        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
444        glyphStorage.setCharIndex(lastGlyph, ia, success);
445        break;
446
447    case irvDCxAB:
448        if (lastGlyph - firstGlyph < 3) {
449            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
450            break;
451        }
452        a = glyphStorage[firstGlyph];
453        b = glyphStorage[firstGlyph + 1];
454
455        glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
456        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1];
457
458        glyphStorage[lastGlyph - 1] = a;
459        glyphStorage[lastGlyph] = b;
460
461        ia = glyphStorage.getCharIndex(firstGlyph, success);
462        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
463        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
464        id = glyphStorage.getCharIndex(lastGlyph, success);
465
466        glyphStorage.setCharIndex(firstGlyph, id, success);
467        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
468
469        glyphStorage.setCharIndex(lastGlyph - 1, ia, success);
470        glyphStorage.setCharIndex(lastGlyph, ib, success);
471        break;
472
473    case irvDCxBA:
474        if (lastGlyph - firstGlyph < 3) {
475            success = LE_INDEX_OUT_OF_BOUNDS_ERROR;
476            break;
477        }
478        a = glyphStorage[firstGlyph];
479        b = glyphStorage[firstGlyph + 1];
480
481        glyphStorage[firstGlyph] = glyphStorage[lastGlyph];
482        glyphStorage[firstGlyph + 1] = glyphStorage[lastGlyph - 1];
483
484        glyphStorage[lastGlyph - 1] = b;
485        glyphStorage[lastGlyph] = a;
486
487        ia = glyphStorage.getCharIndex(firstGlyph, success);
488        ib = glyphStorage.getCharIndex(firstGlyph + 1, success);
489        ic = glyphStorage.getCharIndex(lastGlyph - 1, success);
490        id = glyphStorage.getCharIndex(lastGlyph, success);
491
492        glyphStorage.setCharIndex(firstGlyph, id, success);
493        glyphStorage.setCharIndex(firstGlyph + 1, ic, success);
494
495        glyphStorage.setCharIndex(lastGlyph - 1, ib, success);
496        glyphStorage.setCharIndex(lastGlyph, ia, success);
497        break;
498
499    default:
500        break;
501    }
502}
503
504U_NAMESPACE_END
505