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 
  42 U_NAMESPACE_BEGIN
  43 
  44 UOBJECT_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 
  56 IndicRearrangementProcessor::~IndicRearrangementProcessor()
  57 {
  58 }
  59 
  60 void IndicRearrangementProcessor::beginStateTable()
  61 {
  62     firstGlyph = 0;
  63     lastGlyph = 0;
  64 }
  65 
  66 ByteOffset IndicRearrangementProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index)
  67 {
  68   LEErrorCode success = LE_NO_ERROR; // todo- make a param?
  69   const IndicRearrangementStateEntry *entry = entryTable.getAlias(index,success);
  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 
  96 void IndicRearrangementProcessor::endStateTable()
  97 {
  98 }
  99 
 100 void 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 
 504 U_NAMESPACE_END