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