1 /* GRAPHITE2 LICENSING 2 3 Copyright 2010, SIL International 4 All rights reserved. 5 6 This library is free software; you can redistribute it and/or modify 7 it under the terms of the GNU Lesser General Public License as published 8 by the Free Software Foundation; either version 2.1 of License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should also have received a copy of the GNU Lesser General Public 17 License along with this library in the file named "LICENSE". 18 If not, write to the Free Software Foundation, 51 Franklin Street, 19 Suite 500, Boston, MA 02110-1335, USA or visit their web page on the 20 internet at http://www.fsf.org/licenses/lgpl.html. 21 22 Alternatively, the contents of this file may be used under the terms of the 23 Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public 24 License, as published by the Free Software Foundation, either version 2 25 of the License or (at your option) any later version. 26 */ 27 #pragma once 28 // This file will be pulled into and integrated into a machine implmentation 29 // DO NOT build directly and under no circumstances ever #include headers in 30 // here or you will break the direct_machine. 31 // 32 // Implementers' notes 33 // ================== 34 // You have access to a few primitives and the full C++ code: 35 // declare_params(n) Tells the interpreter how many bytes of parameter 36 // space to claim for this instruction uses and 37 // initialises the param pointer. You *must* before the 38 // first use of param. 39 // use_params(n) Claim n extra bytes of param space beyond what was 40 // claimed using delcare_param. 41 // param A const byte pointer for the parameter space claimed by 42 // this instruction. 43 // binop(op) Implement a binary operation on the stack using the 44 // specified C++ operator. 45 // NOT_IMPLEMENTED Any instruction body containing this will exit the 46 // program with an assertion error. Instructions that are 47 // not implemented should also be marked NILOP in the 48 // opcodes tables this will cause the code class to spot 49 // them in a live code stream and throw a runtime_error 50 // instead. 51 // push(n) Push the value n onto the stack. 52 // pop() Pop the top most value and return it. 53 // 54 // You have access to the following named fast 'registers': 55 // sp = The pointer to the current top of stack, the last value 56 // pushed. 57 // seg = A reference to the Segment this code is running over. 58 // is = The current slot index 59 // isb = The original base slot index at the start of this rule 60 // isf = The first positioned slot 61 // isl = The last positioned slot 62 // ip = The current instruction pointer 63 // endPos = Position of advance of last cluster 64 // dir = writing system directionality of the font 65 66 67 // #define NOT_IMPLEMENTED assert(false) 68 // #define NOT_IMPLEMENTED 69 70 #define binop(op) const uint32 a = pop(); *sp = uint32(*sp) op a 71 #define sbinop(op) const int32 a = pop(); *sp = int32(*sp) op a 72 #define use_params(n) dp += n 73 74 #define declare_params(n) const byte * param = dp; \ 75 use_params(n); 76 77 #define push(n) { *++sp = n; } 78 #define pop() (*sp--) 79 #define slotat(x) (map[(x)]) 80 #define DIE { is=seg.last(); status = Machine::died_early; EXIT(1); } 81 #define POSITIONED 1 82 83 STARTOP(nop) 84 do {} while (0); 85 ENDOP 86 87 STARTOP(push_byte) 88 declare_params(1); 89 push(int8(*param)); 90 ENDOP 91 92 STARTOP(push_byte_u) 93 declare_params(1); 94 push(uint8(*param)); 95 ENDOP 96 97 STARTOP(push_short) 98 declare_params(2); 99 const int16 r = int16(param[0]) << 8 100 | uint8(param[1]); 101 push(r); 102 ENDOP 103 104 STARTOP(push_short_u) 105 declare_params(2); 106 const uint16 r = uint16(param[0]) << 8 107 | uint8(param[1]); 108 push(r); 109 ENDOP 110 111 STARTOP(push_long) 112 declare_params(4); 113 const int32 r = int32(param[0]) << 24 114 | uint32(param[1]) << 16 115 | uint32(param[2]) << 8 116 | uint8(param[3]); 117 push(r); 118 ENDOP 119 120 STARTOP(add) 121 binop(+); 122 ENDOP 123 124 STARTOP(sub) 125 binop(-); 126 ENDOP 127 128 STARTOP(mul) 129 binop(*); 130 ENDOP 131 132 STARTOP(div_) 133 const int32 b = pop(); 134 const int32 a = int32(*sp); 135 if (b == 0 || (a == std::numeric_limits<int32>::min() && b == -1)) DIE; 136 *sp = int32(*sp) / b; 137 ENDOP 138 139 STARTOP(min_) 140 const int32 a = pop(), b = *sp; 141 if (a < b) *sp = a; 142 ENDOP 143 144 STARTOP(max_) 145 const int32 a = pop(), b = *sp; 146 if (a > b) *sp = a; 147 ENDOP 148 149 STARTOP(neg) 150 *sp = uint32(-int32(*sp)); 151 ENDOP 152 153 STARTOP(trunc8) 154 *sp = uint8(*sp); 155 ENDOP 156 157 STARTOP(trunc16) 158 *sp = uint16(*sp); 159 ENDOP 160 161 STARTOP(cond) 162 const uint32 f = pop(), t = pop(), c = pop(); 163 push(c ? t : f); 164 ENDOP 165 166 STARTOP(and_) 167 binop(&&); 168 ENDOP 169 170 STARTOP(or_) 171 binop(||); 172 ENDOP 173 174 STARTOP(not_) 175 *sp = !*sp; 176 ENDOP 177 178 STARTOP(equal) 179 binop(==); 180 ENDOP 181 182 STARTOP(not_eq_) 183 binop(!=); 184 ENDOP 185 186 STARTOP(less) 187 sbinop(<); 188 ENDOP 189 190 STARTOP(gtr) 191 sbinop(>); 192 ENDOP 193 194 STARTOP(less_eq) 195 sbinop(<=); 196 ENDOP 197 198 STARTOP(gtr_eq) 199 sbinop(>=); 200 ENDOP 201 202 STARTOP(next) 203 if (map - &smap[0] >= int(smap.size())) DIE 204 if (is) 205 { 206 if (is == smap.highwater()) 207 smap.highpassed(true); 208 is = is->next(); 209 } 210 ++map; 211 ENDOP 212 213 //STARTOP(next_n) 214 // use_params(1); 215 // NOT_IMPLEMENTED; 216 //declare_params(1); 217 //const size_t num = uint8(*param); 218 //ENDOP 219 220 //STARTOP(copy_next) 221 // if (is) is = is->next(); 222 // ++map; 223 // ENDOP 224 225 STARTOP(put_glyph_8bit_obs) 226 declare_params(1); 227 const unsigned int output_class = uint8(*param); 228 is->setGlyph(&seg, seg.getClassGlyph(output_class, 0)); 229 ENDOP 230 231 STARTOP(put_subs_8bit_obs) 232 declare_params(3); 233 const int slot_ref = int8(param[0]); 234 const unsigned int input_class = uint8(param[1]), 235 output_class = uint8(param[2]); 236 uint16 index; 237 slotref slot = slotat(slot_ref); 238 if (slot) 239 { 240 index = seg.findClassIndex(input_class, slot->gid()); 241 is->setGlyph(&seg, seg.getClassGlyph(output_class, index)); 242 } 243 ENDOP 244 245 STARTOP(put_copy) 246 declare_params(1); 247 const int slot_ref = int8(*param); 248 if (is && !is->isDeleted()) 249 { 250 slotref ref = slotat(slot_ref); 251 if (ref && ref != is) 252 { 253 int16 *tempUserAttrs = is->userAttrs(); 254 if (is->attachedTo() || is->firstChild()) DIE 255 Slot *prev = is->prev(); 256 Slot *next = is->next(); 257 memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16)); 258 memcpy(is, ref, sizeof(Slot)); 259 is->firstChild(NULL); 260 is->nextSibling(NULL); 261 is->userAttrs(tempUserAttrs); 262 is->next(next); 263 is->prev(prev); 264 if (is->attachedTo()) 265 is->attachedTo()->child(is); 266 } 267 is->markCopied(false); 268 is->markDeleted(false); 269 } 270 ENDOP 271 272 STARTOP(insert) 273 if (smap.decMax() <= 0) DIE; 274 Slot *newSlot = seg.newSlot(); 275 if (!newSlot) DIE; 276 Slot *iss = is; 277 while (iss && iss->isDeleted()) iss = iss->next(); 278 if (!iss) 279 { 280 if (seg.last()) 281 { 282 seg.last()->next(newSlot); 283 newSlot->prev(seg.last()); 284 newSlot->before(seg.last()->before()); 285 seg.last(newSlot); 286 } 287 else 288 { 289 seg.first(newSlot); 290 seg.last(newSlot); 291 } 292 } 293 else if (iss->prev()) 294 { 295 iss->prev()->next(newSlot); 296 newSlot->prev(iss->prev()); 297 newSlot->before(iss->prev()->after()); 298 } 299 else 300 { 301 newSlot->prev(NULL); 302 newSlot->before(iss->before()); 303 seg.first(newSlot); 304 } 305 newSlot->next(iss); 306 if (iss) 307 { 308 iss->prev(newSlot); 309 newSlot->originate(iss->original()); 310 newSlot->after(iss->before()); 311 } 312 else if (newSlot->prev()) 313 { 314 newSlot->originate(newSlot->prev()->original()); 315 newSlot->after(newSlot->prev()->after()); 316 } 317 else 318 { 319 newSlot->originate(seg.defaultOriginal()); 320 } 321 if (is == smap.highwater()) 322 smap.highpassed(false); 323 is = newSlot; 324 seg.extendLength(1); 325 if (map != &smap[-1]) 326 --map; 327 ENDOP 328 329 STARTOP(delete_) 330 if (!is || is->isDeleted()) DIE 331 is->markDeleted(true); 332 if (is->prev()) 333 is->prev()->next(is->next()); 334 else 335 seg.first(is->next()); 336 337 if (is->next()) 338 is->next()->prev(is->prev()); 339 else 340 seg.last(is->prev()); 341 342 343 if (is == smap.highwater()) 344 smap.highwater(is->next()); 345 if (is->prev()) 346 is = is->prev(); 347 seg.extendLength(-1); 348 ENDOP 349 350 STARTOP(assoc) 351 declare_params(1); 352 unsigned int num = uint8(*param); 353 const int8 * assocs = reinterpret_cast<const int8 *>(param+1); 354 use_params(num); 355 int max = -1; 356 int min = -1; 357 358 while (num-- > 0) 359 { 360 int sr = *assocs++; 361 slotref ts = slotat(sr); 362 if (ts && (min == -1 || ts->before() < min)) min = ts->before(); 363 if (ts && ts->after() > max) max = ts->after(); 364 } 365 if (min > -1) // implies max > -1 366 { 367 is->before(min); 368 is->after(max); 369 } 370 ENDOP 371 372 STARTOP(cntxt_item) 373 // It turns out this is a cunningly disguised condition forward jump. 374 declare_params(3); 375 const int is_arg = int8(param[0]); 376 const size_t iskip = uint8(param[1]), 377 dskip = uint8(param[2]); 378 379 if (mapb + is_arg != map) 380 { 381 ip += iskip; 382 dp += dskip; 383 push(true); 384 } 385 ENDOP 386 387 STARTOP(attr_set) 388 declare_params(1); 389 const attrCode slat = attrCode(uint8(*param)); 390 const int val = pop(); 391 is->setAttr(&seg, slat, 0, val, smap); 392 ENDOP 393 394 STARTOP(attr_add) 395 declare_params(1); 396 const attrCode slat = attrCode(uint8(*param)); 397 const uint32_t val = pop(); 398 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) 399 { 400 seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); 401 flags |= POSITIONED; 402 } 403 uint32_t res = uint32_t(is->getAttr(&seg, slat, 0)); 404 is->setAttr(&seg, slat, 0, int32_t(val + res), smap); 405 ENDOP 406 407 STARTOP(attr_sub) 408 declare_params(1); 409 const attrCode slat = attrCode(uint8(*param)); 410 const uint32_t val = pop(); 411 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) 412 { 413 seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); 414 flags |= POSITIONED; 415 } 416 uint32_t res = uint32_t(is->getAttr(&seg, slat, 0)); 417 is->setAttr(&seg, slat, 0, int32_t(res - val), smap); 418 ENDOP 419 420 STARTOP(attr_set_slot) 421 declare_params(1); 422 const attrCode slat = attrCode(uint8(*param)); 423 const int offset = int(map - smap.begin())*int(slat == gr_slatAttTo); 424 const int val = pop() + offset; 425 is->setAttr(&seg, slat, offset, val, smap); 426 ENDOP 427 428 STARTOP(iattr_set_slot) 429 declare_params(2); 430 const attrCode slat = attrCode(uint8(param[0])); 431 const uint8 idx = uint8(param[1]); 432 const int val = int(pop() + (map - smap.begin())*int(slat == gr_slatAttTo)); 433 is->setAttr(&seg, slat, idx, val, smap); 434 ENDOP 435 436 STARTOP(push_slot_attr) 437 declare_params(2); 438 const attrCode slat = attrCode(uint8(param[0])); 439 const int slot_ref = int8(param[1]); 440 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) 441 { 442 seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); 443 flags |= POSITIONED; 444 } 445 slotref slot = slotat(slot_ref); 446 if (slot) 447 { 448 int res = slot->getAttr(&seg, slat, 0); 449 push(res); 450 } 451 ENDOP 452 453 STARTOP(push_glyph_attr_obs) 454 declare_params(2); 455 const unsigned int glyph_attr = uint8(param[0]); 456 const int slot_ref = int8(param[1]); 457 slotref slot = slotat(slot_ref); 458 if (slot) 459 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); 460 ENDOP 461 462 STARTOP(push_glyph_metric) 463 declare_params(3); 464 const unsigned int glyph_attr = uint8(param[0]); 465 const int slot_ref = int8(param[1]); 466 const signed int attr_level = uint8(param[2]); 467 slotref slot = slotat(slot_ref); 468 if (slot) 469 push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)); 470 ENDOP 471 472 STARTOP(push_feat) 473 declare_params(2); 474 const unsigned int feat = uint8(param[0]); 475 const int slot_ref = int8(param[1]); 476 slotref slot = slotat(slot_ref); 477 if (slot) 478 { 479 uint8 fid = seg.charinfo(slot->original())->fid(); 480 push(seg.getFeature(fid, feat)); 481 } 482 ENDOP 483 484 STARTOP(push_att_to_gattr_obs) 485 declare_params(2); 486 const unsigned int glyph_attr = uint8(param[0]); 487 const int slot_ref = int8(param[1]); 488 slotref slot = slotat(slot_ref); 489 if (slot) 490 { 491 slotref att = slot->attachedTo(); 492 if (att) slot = att; 493 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); 494 } 495 ENDOP 496 497 STARTOP(push_att_to_glyph_metric) 498 declare_params(3); 499 const unsigned int glyph_attr = uint8(param[0]); 500 const int slot_ref = int8(param[1]); 501 const signed int attr_level = uint8(param[2]); 502 slotref slot = slotat(slot_ref); 503 if (slot) 504 { 505 slotref att = slot->attachedTo(); 506 if (att) slot = att; 507 push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir))); 508 } 509 ENDOP 510 511 STARTOP(push_islot_attr) 512 declare_params(3); 513 const attrCode slat = attrCode(uint8(param[0])); 514 const int slot_ref = int8(param[1]), 515 idx = uint8(param[2]); 516 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) 517 { 518 seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); 519 flags |= POSITIONED; 520 } 521 slotref slot = slotat(slot_ref); 522 if (slot) 523 { 524 int res = slot->getAttr(&seg, slat, idx); 525 push(res); 526 } 527 ENDOP 528 529 #if 0 530 STARTOP(push_iglyph_attr) // not implemented 531 NOT_IMPLEMENTED; 532 ENDOP 533 #endif 534 535 STARTOP(pop_ret) 536 const uint32 ret = pop(); 537 EXIT(ret); 538 ENDOP 539 540 STARTOP(ret_zero) 541 EXIT(0); 542 ENDOP 543 544 STARTOP(ret_true) 545 EXIT(1); 546 ENDOP 547 548 STARTOP(iattr_set) 549 declare_params(2); 550 const attrCode slat = attrCode(uint8(param[0])); 551 const uint8 idx = uint8(param[1]); 552 const int val = pop(); 553 is->setAttr(&seg, slat, idx, val, smap); 554 ENDOP 555 556 STARTOP(iattr_add) 557 declare_params(2); 558 const attrCode slat = attrCode(uint8(param[0])); 559 const uint8 idx = uint8(param[1]); 560 const uint32_t val = pop(); 561 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) 562 { 563 seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); 564 flags |= POSITIONED; 565 } 566 uint32_t res = uint32_t(is->getAttr(&seg, slat, idx)); 567 is->setAttr(&seg, slat, idx, int32_t(val + res), smap); 568 ENDOP 569 570 STARTOP(iattr_sub) 571 declare_params(2); 572 const attrCode slat = attrCode(uint8(param[0])); 573 const uint8 idx = uint8(param[1]); 574 const uint32_t val = pop(); 575 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) 576 { 577 seg.positionSlots(0, *smap.begin(), *(smap.end()-1), seg.currdir()); 578 flags |= POSITIONED; 579 } 580 uint32_t res = uint32_t(is->getAttr(&seg, slat, idx)); 581 is->setAttr(&seg, slat, idx, int32_t(res - val), smap); 582 ENDOP 583 584 STARTOP(push_proc_state) 585 use_params(1); 586 push(1); 587 ENDOP 588 589 STARTOP(push_version) 590 push(0x00030000); 591 ENDOP 592 593 STARTOP(put_subs) 594 declare_params(5); 595 const int slot_ref = int8(param[0]); 596 const unsigned int input_class = uint8(param[1]) << 8 597 | uint8(param[2]); 598 const unsigned int output_class = uint8(param[3]) << 8 599 | uint8(param[4]); 600 slotref slot = slotat(slot_ref); 601 if (slot) 602 { 603 int index = seg.findClassIndex(input_class, slot->gid()); 604 is->setGlyph(&seg, seg.getClassGlyph(output_class, index)); 605 } 606 ENDOP 607 608 #if 0 609 STARTOP(put_subs2) // not implemented 610 NOT_IMPLEMENTED; 611 ENDOP 612 613 STARTOP(put_subs3) // not implemented 614 NOT_IMPLEMENTED; 615 ENDOP 616 #endif 617 618 STARTOP(put_glyph) 619 declare_params(2); 620 const unsigned int output_class = uint8(param[0]) << 8 621 | uint8(param[1]); 622 is->setGlyph(&seg, seg.getClassGlyph(output_class, 0)); 623 ENDOP 624 625 STARTOP(push_glyph_attr) 626 declare_params(3); 627 const unsigned int glyph_attr = uint8(param[0]) << 8 628 | uint8(param[1]); 629 const int slot_ref = int8(param[2]); 630 slotref slot = slotat(slot_ref); 631 if (slot) 632 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); 633 ENDOP 634 635 STARTOP(push_att_to_glyph_attr) 636 declare_params(3); 637 const unsigned int glyph_attr = uint8(param[0]) << 8 638 | uint8(param[1]); 639 const int slot_ref = int8(param[2]); 640 slotref slot = slotat(slot_ref); 641 if (slot) 642 { 643 slotref att = slot->attachedTo(); 644 if (att) slot = att; 645 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); 646 } 647 ENDOP 648 649 STARTOP(temp_copy) 650 slotref newSlot = seg.newSlot(); 651 if (!newSlot || !is) DIE; 652 int16 *tempUserAttrs = newSlot->userAttrs(); 653 memcpy(newSlot, is, sizeof(Slot)); 654 memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16)); 655 newSlot->userAttrs(tempUserAttrs); 656 newSlot->markCopied(true); 657 *map = newSlot; 658 ENDOP 659 660 STARTOP(band) 661 binop(&); 662 ENDOP 663 664 STARTOP(bor) 665 binop(|); 666 ENDOP 667 668 STARTOP(bnot) 669 *sp = ~*sp; 670 ENDOP 671 672 STARTOP(setbits) 673 declare_params(4); 674 const uint16 m = uint16(param[0]) << 8 675 | uint8(param[1]); 676 const uint16 v = uint16(param[2]) << 8 677 | uint8(param[3]); 678 *sp = ((*sp) & ~m) | v; 679 ENDOP 680 681 STARTOP(set_feat) 682 declare_params(2); 683 const unsigned int feat = uint8(param[0]); 684 const int slot_ref = int8(param[1]); 685 slotref slot = slotat(slot_ref); 686 if (slot) 687 { 688 uint8 fid = seg.charinfo(slot->original())->fid(); 689 seg.setFeature(fid, feat, pop()); 690 } 691 ENDOP 692