|
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 every #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 |
|
65 |
|
66 // #define NOT_IMPLEMENTED assert(false) |
|
67 #define NOT_IMPLEMENTED |
|
68 |
|
69 #define binop(op) const int32 a = pop(); *sp = int32(*sp) op a |
|
70 #define use_params(n) dp += n |
|
71 |
|
72 #define declare_params(n) const byte * param = dp; \ |
|
73 use_params(n); |
|
74 |
|
75 #define push(n) { *++sp = n; } |
|
76 #define pop() (*sp--) |
|
77 #define slotat(x) (map[(x)]) |
|
78 #define DIE { is=seg.last(); EXIT(1); } |
|
79 #define POSITIONED 1 |
|
80 |
|
81 STARTOP(nop) |
|
82 do {} while (0); |
|
83 ENDOP |
|
84 |
|
85 STARTOP(push_byte) |
|
86 declare_params(1); |
|
87 push(int8(*param)); |
|
88 ENDOP |
|
89 |
|
90 STARTOP(push_byte_u) |
|
91 declare_params(1); |
|
92 push(uint8(*param)); |
|
93 ENDOP |
|
94 |
|
95 STARTOP(push_short) |
|
96 declare_params(2); |
|
97 const int16 r = int16(param[0]) << 8 |
|
98 | uint8(param[1]); |
|
99 push(r); |
|
100 ENDOP |
|
101 |
|
102 STARTOP(push_short_u) |
|
103 declare_params(2); |
|
104 const uint16 r = uint16(param[0]) << 8 |
|
105 | uint8(param[1]); |
|
106 push(r); |
|
107 ENDOP |
|
108 |
|
109 STARTOP(push_long) |
|
110 declare_params(4); |
|
111 const int32 r = int32(param[0]) << 24 |
|
112 | uint32(param[1]) << 16 |
|
113 | uint32(param[2]) << 8 |
|
114 | uint8(param[3]); |
|
115 push(r); |
|
116 ENDOP |
|
117 |
|
118 STARTOP(add) |
|
119 binop(+); |
|
120 ENDOP |
|
121 |
|
122 STARTOP(sub) |
|
123 binop(-); |
|
124 ENDOP |
|
125 |
|
126 STARTOP(mul) |
|
127 binop(*); |
|
128 ENDOP |
|
129 |
|
130 STARTOP(div_) |
|
131 if (*sp == 0) DIE; |
|
132 binop(/); |
|
133 ENDOP |
|
134 |
|
135 STARTOP(min_) |
|
136 const int32 a = pop(), b = *sp; |
|
137 if (a < b) *sp = a; |
|
138 ENDOP |
|
139 |
|
140 STARTOP(max_) |
|
141 const int32 a = pop(), b = *sp; |
|
142 if (a > b) *sp = a; |
|
143 ENDOP |
|
144 |
|
145 STARTOP(neg) |
|
146 *sp = uint32(-int32(*sp)); |
|
147 ENDOP |
|
148 |
|
149 STARTOP(trunc8) |
|
150 *sp = uint8(*sp); |
|
151 ENDOP |
|
152 |
|
153 STARTOP(trunc16) |
|
154 *sp = uint16(*sp); |
|
155 ENDOP |
|
156 |
|
157 STARTOP(cond) |
|
158 const uint32 f = pop(), t = pop(), c = pop(); |
|
159 push(c ? t : f); |
|
160 ENDOP |
|
161 |
|
162 STARTOP(and_) |
|
163 binop(&&); |
|
164 ENDOP |
|
165 |
|
166 STARTOP(or_) |
|
167 binop(||); |
|
168 ENDOP |
|
169 |
|
170 STARTOP(not_) |
|
171 *sp = !*sp; |
|
172 ENDOP |
|
173 |
|
174 STARTOP(equal) |
|
175 binop(==); |
|
176 ENDOP |
|
177 |
|
178 STARTOP(not_eq_) |
|
179 binop(!=); |
|
180 ENDOP |
|
181 |
|
182 STARTOP(less) |
|
183 binop(<); |
|
184 ENDOP |
|
185 |
|
186 STARTOP(gtr) |
|
187 binop(>); |
|
188 ENDOP |
|
189 |
|
190 STARTOP(less_eq) |
|
191 binop(<=); |
|
192 ENDOP |
|
193 |
|
194 STARTOP(gtr_eq) |
|
195 binop(>=); |
|
196 ENDOP |
|
197 |
|
198 STARTOP(next) |
|
199 if (map - &smap[0] >= int(smap.size())) DIE |
|
200 if (is) |
|
201 { |
|
202 if (is == smap.highwater()) |
|
203 smap.highpassed(true); |
|
204 is = is->next(); |
|
205 } |
|
206 ++map; |
|
207 ENDOP |
|
208 |
|
209 STARTOP(next_n) |
|
210 use_params(1); |
|
211 NOT_IMPLEMENTED; |
|
212 //declare_params(1); |
|
213 //const size_t num = uint8(*param); |
|
214 ENDOP |
|
215 |
|
216 //STARTOP(copy_next) |
|
217 // if (is) is = is->next(); |
|
218 // ++map; |
|
219 // ENDOP |
|
220 |
|
221 STARTOP(put_glyph_8bit_obs) |
|
222 declare_params(1); |
|
223 const unsigned int output_class = uint8(*param); |
|
224 is->setGlyph(&seg, seg.getClassGlyph(output_class, 0)); |
|
225 ENDOP |
|
226 |
|
227 STARTOP(put_subs_8bit_obs) |
|
228 declare_params(3); |
|
229 const int slot_ref = int8(param[0]); |
|
230 const unsigned int input_class = uint8(param[1]), |
|
231 output_class = uint8(param[2]); |
|
232 uint16 index; |
|
233 slotref slot = slotat(slot_ref); |
|
234 if (slot) |
|
235 { |
|
236 index = seg.findClassIndex(input_class, slot->gid()); |
|
237 is->setGlyph(&seg, seg.getClassGlyph(output_class, index)); |
|
238 } |
|
239 ENDOP |
|
240 |
|
241 STARTOP(put_copy) |
|
242 declare_params(1); |
|
243 const int slot_ref = int8(*param); |
|
244 if (is && (slot_ref ||is != *map)) |
|
245 { |
|
246 int16 *tempUserAttrs = is->userAttrs(); |
|
247 slotref ref = slotat(slot_ref); |
|
248 if (ref) |
|
249 { |
|
250 memcpy(tempUserAttrs, ref->userAttrs(), seg.numAttrs() * sizeof(uint16)); |
|
251 Slot *prev = is->prev(); |
|
252 Slot *next = is->next(); |
|
253 memcpy(is, slotat(slot_ref), sizeof(Slot)); |
|
254 is->userAttrs(tempUserAttrs); |
|
255 is->next(next); |
|
256 is->prev(prev); |
|
257 is->sibling(NULL); |
|
258 } |
|
259 is->markCopied(false); |
|
260 is->markDeleted(false); |
|
261 } |
|
262 ENDOP |
|
263 |
|
264 STARTOP(insert) |
|
265 Slot *newSlot = seg.newSlot(); |
|
266 if (!newSlot) DIE; |
|
267 Slot *iss = is; |
|
268 while (iss && iss->isDeleted()) iss = iss->next(); |
|
269 if (!iss) |
|
270 { |
|
271 if (seg.last()) |
|
272 { |
|
273 seg.last()->next(newSlot); |
|
274 newSlot->prev(seg.last()); |
|
275 newSlot->before(seg.last()->before()); |
|
276 seg.last(newSlot); |
|
277 } |
|
278 else |
|
279 { |
|
280 seg.first(newSlot); |
|
281 seg.last(newSlot); |
|
282 } |
|
283 } |
|
284 else if (iss->prev()) |
|
285 { |
|
286 iss->prev()->next(newSlot); |
|
287 newSlot->prev(iss->prev()); |
|
288 newSlot->before(iss->prev()->after()); |
|
289 } |
|
290 else |
|
291 { |
|
292 newSlot->prev(NULL); |
|
293 newSlot->before(iss->before()); |
|
294 seg.first(newSlot); |
|
295 } |
|
296 newSlot->next(iss); |
|
297 if (iss) |
|
298 { |
|
299 iss->prev(newSlot); |
|
300 newSlot->originate(iss->original()); |
|
301 newSlot->after(iss->before()); |
|
302 } |
|
303 else if (newSlot->prev()) |
|
304 { |
|
305 newSlot->originate(newSlot->prev()->original()); |
|
306 newSlot->after(newSlot->prev()->after()); |
|
307 } |
|
308 else |
|
309 { |
|
310 newSlot->originate(seg.defaultOriginal()); |
|
311 } |
|
312 is = newSlot; |
|
313 seg.extendLength(1); |
|
314 if (map != &smap[-1]) |
|
315 --map; |
|
316 ENDOP |
|
317 |
|
318 STARTOP(delete_) |
|
319 if (!is) DIE |
|
320 is->markDeleted(true); |
|
321 if (is->prev()) |
|
322 is->prev()->next(is->next()); |
|
323 else |
|
324 seg.first(is->next()); |
|
325 |
|
326 if (is->next()) |
|
327 is->next()->prev(is->prev()); |
|
328 else |
|
329 seg.last(is->prev()); |
|
330 |
|
331 if (is == smap.highwater()) |
|
332 smap.highwater(is->next()); |
|
333 if (is->prev()) |
|
334 is = is->prev(); |
|
335 seg.extendLength(-1); |
|
336 ENDOP |
|
337 |
|
338 STARTOP(assoc) |
|
339 declare_params(1); |
|
340 unsigned int num = uint8(*param); |
|
341 const int8 * assocs = reinterpret_cast<const int8 *>(param+1); |
|
342 use_params(num); |
|
343 int max = -1; |
|
344 int min = -1; |
|
345 |
|
346 while (num-- > 0) |
|
347 { |
|
348 int sr = *assocs++; |
|
349 slotref ts = slotat(sr); |
|
350 if (ts && (min == -1 || ts->before() < min)) min = ts->before(); |
|
351 if (ts && ts->after() > max) max = ts->after(); |
|
352 } |
|
353 if (min > -1) // implies max > -1 |
|
354 { |
|
355 is->before(min); |
|
356 is->after(max); |
|
357 } |
|
358 ENDOP |
|
359 |
|
360 STARTOP(cntxt_item) |
|
361 // It turns out this is a cunningly disguised condition forward jump. |
|
362 declare_params(3); |
|
363 const int is_arg = int8(param[0]); |
|
364 const size_t iskip = uint8(param[1]), |
|
365 dskip = uint8(param[2]); |
|
366 |
|
367 if (mapb + is_arg != map) |
|
368 { |
|
369 ip += iskip; |
|
370 dp += dskip; |
|
371 push(true); |
|
372 } |
|
373 ENDOP |
|
374 |
|
375 STARTOP(attr_set) |
|
376 declare_params(1); |
|
377 const attrCode slat = attrCode(uint8(*param)); |
|
378 const int val = int(pop()); |
|
379 is->setAttr(&seg, slat, 0, val, smap); |
|
380 ENDOP |
|
381 |
|
382 STARTOP(attr_add) |
|
383 declare_params(1); |
|
384 const attrCode slat = attrCode(uint8(*param)); |
|
385 const int val = int(pop()); |
|
386 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) |
|
387 { |
|
388 seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); |
|
389 flags |= POSITIONED; |
|
390 } |
|
391 int res = is->getAttr(&seg, slat, 0); |
|
392 is->setAttr(&seg, slat, 0, val + res, smap); |
|
393 ENDOP |
|
394 |
|
395 STARTOP(attr_sub) |
|
396 declare_params(1); |
|
397 const attrCode slat = attrCode(uint8(*param)); |
|
398 const int val = int(pop()); |
|
399 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) |
|
400 { |
|
401 seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); |
|
402 flags |= POSITIONED; |
|
403 } |
|
404 int res = is->getAttr(&seg, slat, 0); |
|
405 is->setAttr(&seg, slat, 0, res - val, smap); |
|
406 ENDOP |
|
407 |
|
408 STARTOP(attr_set_slot) |
|
409 declare_params(1); |
|
410 const attrCode slat = attrCode(uint8(*param)); |
|
411 const int offset = (map - smap.begin())*int(slat == gr_slatAttTo); |
|
412 const int val = int(pop()) + offset; |
|
413 is->setAttr(&seg, slat, offset, val, smap); |
|
414 ENDOP |
|
415 |
|
416 STARTOP(iattr_set_slot) |
|
417 declare_params(2); |
|
418 const attrCode slat = attrCode(uint8(param[0])); |
|
419 const size_t idx = uint8(param[1]); |
|
420 const int val = int(pop()) + (map - smap.begin())*int(slat == gr_slatAttTo); |
|
421 is->setAttr(&seg, slat, idx, val, smap); |
|
422 ENDOP |
|
423 |
|
424 STARTOP(push_slot_attr) |
|
425 declare_params(2); |
|
426 const attrCode slat = attrCode(uint8(param[0])); |
|
427 const int slot_ref = int8(param[1]); |
|
428 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) |
|
429 { |
|
430 seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); |
|
431 flags |= POSITIONED; |
|
432 } |
|
433 slotref slot = slotat(slot_ref); |
|
434 if (slot) |
|
435 { |
|
436 int res = slot->getAttr(&seg, slat, 0); |
|
437 push(res); |
|
438 } |
|
439 ENDOP |
|
440 |
|
441 STARTOP(push_glyph_attr_obs) |
|
442 declare_params(2); |
|
443 const unsigned int glyph_attr = uint8(param[0]); |
|
444 const int slot_ref = int8(param[1]); |
|
445 slotref slot = slotat(slot_ref); |
|
446 if (slot) |
|
447 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); |
|
448 ENDOP |
|
449 |
|
450 STARTOP(push_glyph_metric) |
|
451 declare_params(3); |
|
452 const unsigned int glyph_attr = uint8(param[0]); |
|
453 const int slot_ref = int8(param[1]); |
|
454 const signed int attr_level = uint8(param[2]); |
|
455 slotref slot = slotat(slot_ref); |
|
456 if (slot) |
|
457 push(seg.getGlyphMetric(slot, glyph_attr, attr_level)); |
|
458 ENDOP |
|
459 |
|
460 STARTOP(push_feat) |
|
461 declare_params(2); |
|
462 const unsigned int feat = uint8(param[0]); |
|
463 const int slot_ref = int8(param[1]); |
|
464 slotref slot = slotat(slot_ref); |
|
465 if (slot) |
|
466 { |
|
467 uint8 fid = seg.charinfo(slot->original())->fid(); |
|
468 push(seg.getFeature(fid, feat)); |
|
469 } |
|
470 ENDOP |
|
471 |
|
472 STARTOP(push_att_to_gattr_obs) |
|
473 declare_params(2); |
|
474 const unsigned int glyph_attr = uint8(param[0]); |
|
475 const int slot_ref = int8(param[1]); |
|
476 slotref slot = slotat(slot_ref); |
|
477 if (slot) |
|
478 { |
|
479 slotref att = slot->attachedTo(); |
|
480 if (att) slot = att; |
|
481 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); |
|
482 } |
|
483 ENDOP |
|
484 |
|
485 STARTOP(push_att_to_glyph_metric) |
|
486 declare_params(3); |
|
487 const unsigned int glyph_attr = uint8(param[0]); |
|
488 const int slot_ref = int8(param[1]); |
|
489 const signed int attr_level = uint8(param[2]); |
|
490 slotref slot = slotat(slot_ref); |
|
491 if (slot) |
|
492 { |
|
493 slotref att = slot->attachedTo(); |
|
494 if (att) slot = att; |
|
495 push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level))); |
|
496 } |
|
497 ENDOP |
|
498 |
|
499 STARTOP(push_islot_attr) |
|
500 declare_params(3); |
|
501 const attrCode slat = attrCode(uint8(param[0])); |
|
502 const int slot_ref = int8(param[1]), |
|
503 idx = uint8(param[2]); |
|
504 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) |
|
505 { |
|
506 seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); |
|
507 flags |= POSITIONED; |
|
508 } |
|
509 slotref slot = slotat(slot_ref); |
|
510 if (slot) |
|
511 { |
|
512 int res = slot->getAttr(&seg, slat, idx); |
|
513 push(res); |
|
514 } |
|
515 ENDOP |
|
516 |
|
517 #if 0 |
|
518 STARTOP(push_iglyph_attr) // not implemented |
|
519 NOT_IMPLEMENTED; |
|
520 ENDOP |
|
521 #endif |
|
522 |
|
523 STARTOP(pop_ret) |
|
524 const uint32 ret = pop(); |
|
525 EXIT(ret); |
|
526 ENDOP |
|
527 |
|
528 STARTOP(ret_zero) |
|
529 EXIT(0); |
|
530 ENDOP |
|
531 |
|
532 STARTOP(ret_true) |
|
533 EXIT(1); |
|
534 ENDOP |
|
535 |
|
536 STARTOP(iattr_set) |
|
537 declare_params(2); |
|
538 const attrCode slat = attrCode(uint8(param[0])); |
|
539 const size_t idx = uint8(param[1]); |
|
540 const int val = int(pop()); |
|
541 is->setAttr(&seg, slat, idx, val, smap); |
|
542 ENDOP |
|
543 |
|
544 STARTOP(iattr_add) |
|
545 declare_params(2); |
|
546 const attrCode slat = attrCode(uint8(param[0])); |
|
547 const size_t idx = uint8(param[1]); |
|
548 const int val = int(pop()); |
|
549 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) |
|
550 { |
|
551 seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); |
|
552 flags |= POSITIONED; |
|
553 } |
|
554 int res = is->getAttr(&seg, slat, idx); |
|
555 is->setAttr(&seg, slat, idx, val + res, smap); |
|
556 ENDOP |
|
557 |
|
558 STARTOP(iattr_sub) |
|
559 declare_params(2); |
|
560 const attrCode slat = attrCode(uint8(param[0])); |
|
561 const size_t idx = uint8(param[1]); |
|
562 const int val = int(pop()); |
|
563 if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0) |
|
564 { |
|
565 seg.positionSlots(0, *smap.begin(), *(smap.end()-1)); |
|
566 flags |= POSITIONED; |
|
567 } |
|
568 int res = is->getAttr(&seg, slat, idx); |
|
569 is->setAttr(&seg, slat, idx, res - val, smap); |
|
570 ENDOP |
|
571 |
|
572 STARTOP(push_proc_state) |
|
573 use_params(1); |
|
574 push(1); |
|
575 ENDOP |
|
576 |
|
577 STARTOP(push_version) |
|
578 push(0x00030000); |
|
579 ENDOP |
|
580 |
|
581 STARTOP(put_subs) |
|
582 declare_params(5); |
|
583 const int slot_ref = int8(param[0]); |
|
584 const unsigned int input_class = uint8(param[1]) << 8 |
|
585 | uint8(param[2]); |
|
586 const unsigned int output_class = uint8(param[3]) << 8 |
|
587 | uint8(param[4]); |
|
588 slotref slot = slotat(slot_ref); |
|
589 if (slot) |
|
590 { |
|
591 int index = seg.findClassIndex(input_class, slot->gid()); |
|
592 is->setGlyph(&seg, seg.getClassGlyph(output_class, index)); |
|
593 } |
|
594 ENDOP |
|
595 |
|
596 #if 0 |
|
597 STARTOP(put_subs2) // not implemented |
|
598 NOT_IMPLEMENTED; |
|
599 ENDOP |
|
600 |
|
601 STARTOP(put_subs3) // not implemented |
|
602 NOT_IMPLEMENTED; |
|
603 ENDOP |
|
604 #endif |
|
605 |
|
606 STARTOP(put_glyph) |
|
607 declare_params(2); |
|
608 const unsigned int output_class = uint8(param[0]) << 8 |
|
609 | uint8(param[1]); |
|
610 is->setGlyph(&seg, seg.getClassGlyph(output_class, 0)); |
|
611 ENDOP |
|
612 |
|
613 STARTOP(push_glyph_attr) |
|
614 declare_params(3); |
|
615 const unsigned int glyph_attr = uint8(param[0]) << 8 |
|
616 | uint8(param[1]); |
|
617 const int slot_ref = int8(param[2]); |
|
618 slotref slot = slotat(slot_ref); |
|
619 if (slot) |
|
620 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); |
|
621 ENDOP |
|
622 |
|
623 STARTOP(push_att_to_glyph_attr) |
|
624 declare_params(3); |
|
625 const unsigned int glyph_attr = uint8(param[0]) << 8 |
|
626 | uint8(param[1]); |
|
627 const int slot_ref = int8(param[2]); |
|
628 slotref slot = slotat(slot_ref); |
|
629 if (slot) |
|
630 { |
|
631 slotref att = slot->attachedTo(); |
|
632 if (att) slot = att; |
|
633 push(int32(seg.glyphAttr(slot->gid(), glyph_attr))); |
|
634 } |
|
635 ENDOP |
|
636 |
|
637 STARTOP(temp_copy) |
|
638 slotref newSlot = seg.newSlot(); |
|
639 if (!newSlot) DIE; |
|
640 int16 *tempUserAttrs = newSlot->userAttrs(); |
|
641 memcpy(newSlot, is, sizeof(Slot)); |
|
642 memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16)); |
|
643 newSlot->userAttrs(tempUserAttrs); |
|
644 newSlot->markCopied(true); |
|
645 *map = newSlot; |
|
646 ENDOP |