OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [java/] [awt/] [font/] [opentype/] [truetype/] [VirtualMachine.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* VirtualMachine.java -- Virtual machine for TrueType bytecodes.
2
   Copyright (C) 2006 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package gnu.java.awt.font.opentype.truetype;
39
 
40
import gnu.java.lang.CPStringBuilder;
41
 
42
import java.awt.FontFormatException;
43
import java.awt.geom.AffineTransform;
44
import java.nio.ByteBuffer;
45
import java.nio.ShortBuffer;
46
 
47
 
48
/**
49
 * A virtual machine for interpreting TrueType bytecodes.
50
 *
51
 * <p><b>Lack of Thread Safety:</b> The virtual machine is
52
 * intentionally <i>not</i> safe to access from multiple concurrent
53
 * threads. Synchronization needs to be performed externally. Usually,
54
 * the font has already obtained a lock before calling the scaler,
55
 * which in turn calls the VM. It would be wasteful to acquire
56
 * additional locks for the VM.
57
 *
58
 * <p><b>Implementation Status:</b> The current implementation can
59
 * execute pre-programs of fonts, but it does not yet actually move
60
 * any points. Control flow and arithmeti instructions are
61
 * implemented, but most geometric instructions are not working
62
 * yet. So, the VirtualMachine class is currently a no-op.  However,
63
 * not very much is missing. You are more than welcome to complete the
64
 * implementation.
65
 *
66
 * <p><b>Patents:</b> Apple Computer holds three United States Patents
67
 * for the mathematical algorithms that are used by TrueType
68
 * instructions. The monopoly granted by these patents will expire in
69
 * October 2009. Before the expiration date, a license must be
70
 * obtained from Apple Computer to use the patented technology inside
71
 * the United States. For other countries, different dates might
72
 * apply, or no license might be needed.
73
 *
74
 * <p>The default build of this class does not use the patented
75
 * algorithms.  If you have obtained a license from Apple, or if the
76
 * patent protection has expired, or if no license is required for
77
 * your contry, you can set a flag in the source file which will
78
 * enable the use of the patented mathematical algorithms.</p>
79
 *
80
 * <p>The relevant patents are listed subsequently.</p>
81
 *
82
 * <p><ol><li>United States Patent 5155805, <i>Method and Apparatus
83
 * for Moving Control Points in Displaying Digital Typeface on Raster
84
 * Output Devices,</i> invented by Sampo Kaasila, assigned to Apple
85
 * Computer. Filing date: May 8, 1989. Date of patent: October 13,
86
 * 1992.</li>
87
 *
88
 * <li>United States Patent 5159668, <i>Method and Apparatus for
89
 * Manipulating Outlines in Improving Digital Typeface on Raster
90
 * Output Devices,</i> invented by Sampo Kaasila, assigned to Apple
91
 * Computer. Filing date: May 8, 1989. Date of patent: October 27,
92
 * 1992.</li>
93
 *
94
 * <li>United States Patent 5325479, <i>Method and Apparatus for
95
 * Moving Control Points in Displaying Digital Typeface on Raster
96
 * Output Devices,</i> invented by Sampo Kaasila, assigned to Apple
97
 * Computer. Filing date: May 28, 1989. Date of patent: June 28, 1994
98
 * (with a statement that &#x201c;[t]he portion of the term of this
99
 * patent subsequent to Oct. 13, 2009 has been
100
 * disclaimed&#x201d;).</li></ol>
101
 *
102
 * @author Sascha Brawer (brawer@dandelis.ch)
103
 */
104
class VirtualMachine
105
{
106
  /**
107
   * Indicates whether or not to perform hinting operations that are
108
   * protected by a number of US patents, two of which will expire on
109
   * October 13, 2009, and one of which will expire on October 27,
110
   * 2009.
111
   */
112
  private final static boolean PATENTED_HINTING = false;
113
 
114
 
115
  /**
116
   * Indicates whether the execution of the Virtual Machine is traced
117
   * to System.out.
118
   */
119
  private final static boolean TRACE_EXECUTION = false;
120
 
121
 
122
  /**
123
   * The value 1 in 2-dot-14 fixed notation.
124
   */
125
  private static final short ONE_214 = 0x4000; // 1 << 14
126
 
127
 
128
  /**
129
   * The storage area of the virtual machine.
130
   */
131
  private final int[] storage;
132
 
133
 
134
  /**
135
   * The stack. The stack grows from bottom to top, so
136
   * <code>sp[0]</code> gets used before <code>sp[1]</code>.
137
   */
138
  private int[] stack;
139
 
140
 
141
  /**
142
   * The maximum number of stack elements.
143
   */
144
  private final int maxStackElements;
145
 
146
 
147
  /**
148
   * The current stack pointer of the virtual machine.
149
   */
150
  private int sp;
151
 
152
 
153
  /**
154
   * fdefBuffer[i] is the buffer that contains the TrueType
155
   * instructions of function #i. Most of the time, functions are
156
   * defined in the font program, but a font may also re-define
157
   * functions in its CVT program.
158
   */
159
  private ByteBuffer[] fdefBuffer;
160
 
161
 
162
  /**
163
   * fdefEntryPoint[i] is the position in fdefBuffer[i] where the
164
   * first TrueType instruction after the FDEF is located.
165
   */
166
  private int[] fdefEntryPoint;
167
 
168
 
169
  /**
170
   * The original Control Value Table, sometimes abbreviated as CVT.
171
   * The table contains signed 16-bit FUnits. Some fonts have no CVT,
172
   * in which case the field will be <code>null</code>.
173
   */
174
  private ShortBuffer controlValueTable;
175
 
176
 
177
  /**
178
   * The scaled values inside the control value table.
179
   */
180
  private int[] cvt;
181
 
182
 
183
  /**
184
   * A value that is used by rounding operations to compensate for dot
185
   * gain.
186
   */
187
  private int engineCompensation = 0;
188
 
189
 
190
  /**
191
   * The contents of the font&#x2019;s <code>fpgm</code> table, or
192
   * <code>null</code> after the font program has been executed once.
193
   */
194
  private ByteBuffer fontProgram;
195
 
196
 
197
  /**
198
   * The <code>prep</code> table of the font, which contains a program
199
   * that is executed whenever the point size or the device transform
200
   * have changed.  This program is called pre-program because it gets
201
   * executed before the instructions of the individual glyphs.  If
202
   * the font does not contain a pre-program, the value of this field
203
   * is <code>null</code>.
204
   */
205
  private ByteBuffer preProgram;
206
 
207
 
208
  /**
209
   * The number of points in the Twilight Zone.
210
   */
211
  private int numTwilightPoints;
212
 
213
 
214
  /**
215
   * The current point size of the scaled font. The value is in Fixed
216
   * 26.6 notation.
217
   */
218
  private int pointSize; // 26.6
219
 
220
  private AffineTransform deviceTransform;
221
 
222
  private int scaleX, scaleY, shearX, shearY; // 26.6
223
 
224
 
225
  /**
226
   * Indicates whether or not scan-line conversion will use
227
   * anti-aliasing (with gray levels). Font programs can ask for this
228
   * value with the <code>GETINFO</code> instruction, and some
229
   * programs may behave differently according to this setting.
230
   */
231
  private boolean antialiased;
232
 
233
 
234
  /* Graphics State. FIXME: Move this to its own class? Some
235
   * documentation would not hurt, either.
236
   */
237
  private int cvtCutIn; // 26.6
238
  private int deltaBase; // uint32
239
  private int deltaShift; // uint32
240
  private short freeX; // 2.14
241
  private short freeY; // 2.14
242
  private int loop; // int
243
  private int minimumDistance; // 26.6
244
  private short projX; // 2.14
245
  private short projY; // 2.14
246
  private short dualX; // 2.14
247
  private short dualY; // 2.14
248
  private int rp0, rp1, rp2; // point numbers
249
  private boolean scanControl;
250
  private int scanType;
251
  private int singleWidthValue; // 26.6
252
  private Zone zp0, zp1, zp2;
253
 
254
  private Zone twilightZone;
255
  private Zone glyphZone;
256
 
257
 
258
  /**
259
   * Indicates whether or not the instructions that are associated
260
   * with individual glyphs shall be executed.  Set as a side effect
261
   * of executing the pre-program when the point size, device
262
   * transform or some other relevant parameter have changed.
263
   */
264
  private boolean executeGlyphInstructions;
265
 
266
 
267
  /**
268
   * Indicates whether to ignore any modifications to the control
269
   * value table that the font&#x2019;s pre-program might have
270
   * performed.  Set as a side effect of executing the pre-program
271
   * when the point size, device transform or some other relevant
272
   * parameter have changed.
273
   */
274
  private boolean ignoreCVTProgram;
275
 
276
 
277
  /**
278
   * The length of the space between rounded values. A value
279
   * of zero means that rounding has been switched off.
280
   */
281
  private int roundPeriod; // 26.6
282
 
283
 
284
  /**
285
   * The offset of the rounded values from multiples of
286
   * <code>roundPeriod</code>.
287
   */
288
  private int roundPhase; // 26.6
289
 
290
 
291
  private int roundThreshold; // 26.6
292
 
293
 
294
  /**
295
   * A cache for the number of pixels per EM. The value is a normal
296
   * integer, not a fixed point notation.
297
   *
298
   * @see #getPixelsPerEM()
299
   */
300
  private int cachedPixelsPerEM;
301
 
302
 
303
  /**
304
   * The number of font units per EM.
305
   */
306
  private int unitsPerEm;
307
 
308
 
309
  /**
310
   * Constructs a new Virtual Machine for executing TrueType
311
   * instructions.
312
   *
313
   * @param unitsPerEm the number of font units in one typographic
314
   * em.
315
   *
316
   * @param preProgram the <code>prep</code> table of the font, which
317
   * contains a program that is executed whenever the point size or
318
   * the device transform have changed.  This program is called
319
   * pre-program because it gets executed before the instructions of
320
   * the individual glyphs.  If the font does not contain a
321
   * pre-program, pass <code>null</code>.
322
   */
323
  VirtualMachine(int unitsPerEm,
324
                 ByteBuffer maxp,
325
                 ByteBuffer controlValueTable,
326
                 ByteBuffer fontProgram,
327
                 ByteBuffer preProgram)
328
    throws FontFormatException
329
  {
330
    int maxStorage, numFunctionDefs, maxInstructionDefs;
331
 
332
    if (maxp.getInt(0) != 0x00010000)
333
      throw new FontFormatException("unsupported maxp version");
334
 
335
    this.unitsPerEm = unitsPerEm;
336
    maxStorage = maxp.getChar(18);
337
 
338
    /* FreeType says that there exist some broken fonts (like
339
     * "Keystrokes MT") that contain function defs, but have a zero
340
     * value in their maxp table.
341
     */
342
    numFunctionDefs = maxp.getChar(20);
343
    if (numFunctionDefs == 0)
344
      numFunctionDefs = 64;
345
    fdefBuffer = new ByteBuffer[numFunctionDefs];
346
    fdefEntryPoint = new int[numFunctionDefs];
347
 
348
    /* Read the contents of the Control Value Table. */
349
    if (controlValueTable != null)
350
      this.controlValueTable = controlValueTable.asShortBuffer();
351
 
352
    maxInstructionDefs = maxp.getChar(22);
353
    maxStackElements = maxp.getChar(24);
354
    storage = new int[maxStorage];
355
    this.fontProgram = fontProgram;
356
    this.preProgram = preProgram;
357
    numTwilightPoints = maxp.getChar(16);
358
  }
359
 
360
 
361
  /**
362
   * Sets the graphics state to default values.
363
   */
364
  private void resetGraphicsState()
365
  {
366
    /* The freedom, projection and dual vector default to the x axis. */
367
    freeX = projX = dualX = ONE_214;
368
    freeY = projY = dualX = 0;
369
    cachedPixelsPerEM = 0;
370
 
371
    cvtCutIn = 68; // 17/16 in 26.6 notation
372
    deltaBase = 9;
373
    deltaShift = 3;
374
    loop = 1;
375
    minimumDistance = Fixed.ONE;
376
    singleWidthValue = 0;
377
    rp0 = rp1 = rp2 = 0;
378
    scanControl = false;
379
    scanType = 2;
380
    zp0 = zp1 = zp2 = getZone(1);
381
 
382
    setRoundingMode(Fixed.ONE, 0x48); // round to grid
383
  }
384
 
385
 
386
  /**
387
   * Reloads the control value table and scales each entry from font
388
   * units to pixel values.
389
   */
390
  private void reloadControlValueTable()
391
  {
392
    /* Some TrueType fonts have no control value table. */
393
    if (controlValueTable == null)
394
      return;
395
 
396
    /* Read in the Control Value Table. */
397
    if (cvt == null)
398
      cvt = new int[controlValueTable.capacity()];
399
 
400
    /* Scale the entries. */
401
    for (int i = 0; i < cvt.length; i++)
402
      cvt[i] = funitsToPixels(controlValueTable.get(i));
403
  }
404
 
405
 
406
  /**
407
   * Scales a value from font unites to pixels.
408
   *
409
   * @return the scaled value.
410
   */
411
  private int funitsToPixels(int funits)
412
  {
413
    return (int) (((long) funits * scaleY + (unitsPerEm>>1))
414
                  / unitsPerEm);
415
  }
416
 
417
 
418
  /**
419
   * Sets up the virtual machine for the specified parameters.  If
420
   * there is no change to the last set-up, the method will quickly
421
   * return. Otherwise, the font&#x2019;s pre-program will be
422
   * executed.
423
   *
424
   * @param pointSize the point size of the scaled font.
425
   *
426
   * @param deviceTransform an affine transformation which gets
427
   * applied in addition to scaling by <code>pointSize</code>.  Font
428
   * programs can separately inquire about the point size.  For this
429
   * reason, it is not recommended to pre-multiply the point size to
430
   * the device transformation.
431
   *
432
   * @param antialiased <code>true</code> if the scan-line conversion
433
   * algorithm will use gray levels to give a smoother appearance,
434
   * <code>false</code> otherwise.  Font programs can ask for this
435
   * value with the <code>GETINFO</code> instruction, and some
436
   * programs may behave differently according to this setting.
437
   */
438
  public boolean setup(double pointSize,
439
                       AffineTransform deviceTransform,
440
                       boolean antialiased)
441
  {
442
    boolean changeCTM;
443
    int pointSize_Fixed;
444
 
445
    if (stack == null)
446
      stack = new int[maxStackElements];
447
 
448
    if (twilightZone == null)
449
      twilightZone = new Zone(numTwilightPoints);
450
 
451
    /* If the font program has not yet been executed, do so. */
452
    if (fontProgram != null)
453
    {
454
      resetGraphicsState();
455
      sp = -1;
456
      execute(fontProgram, 0);
457
      fontProgram = null; // prevent further execution
458
    }
459
 
460
    /* Determine whether the transformation matrix has changed. */
461
    pointSize_Fixed = Fixed.valueOf(pointSize);
462
    changeCTM = ((pointSize_Fixed != this.pointSize)
463
                 || !deviceTransform.equals(this.deviceTransform)
464
                 || (antialiased != this.antialiased));
465
 
466
    if (changeCTM)
467
    {
468
      this.pointSize = pointSize_Fixed;
469
      this.deviceTransform = deviceTransform;
470
      this.antialiased = antialiased;
471
      scaleX = (int) (deviceTransform.getScaleX() * pointSize * 64);
472
      scaleY = (int) (deviceTransform.getScaleY() * pointSize * 64);
473
      shearX = (int) (deviceTransform.getShearX() * pointSize * 64);
474
      shearY = (int) (deviceTransform.getShearY() * pointSize * 64);
475
 
476
      resetGraphicsState();
477
      reloadControlValueTable();
478
      executeGlyphInstructions = true;
479
      ignoreCVTProgram = false;
480
 
481
      if (preProgram != null)
482
      {
483
        sp = -1;
484
        execute(preProgram, 0);
485
        if (ignoreCVTProgram)
486
          reloadControlValueTable();
487
      }
488
    }
489
 
490
    return executeGlyphInstructions;
491
  }
492
 
493
 
494
  /**
495
   * Executes a stream of TrueType instructions.
496
   */
497
  private void execute(ByteBuffer instructions, int pos)
498
  {
499
    instructions.position(pos);
500
 
501
    // FIXME: SECURITY: Possible denial-of-service attack
502
    // via instructions that have an endless loop.
503
    while (instructions.hasRemaining()
504
           && executeInstruction(instructions))
505
      ;
506
  }
507
 
508
 
509
  /**
510
   * Writes a textual description of the current TrueType instruction,
511
   * including the top stack elements, to <code>System.out</code>.
512
   * This is useful for debugging.
513
   *
514
   * @param inst the instruction stream, positioned at the current
515
   * instruction.
516
   */
517
  private void dumpInstruction(ByteBuffer inst)
518
  {
519
    CPStringBuilder sbuf = new CPStringBuilder(40);
520
    int pc = inst.position();
521
    int bcode = inst.get(pc) & 0xff;
522
    int count;
523
    int delta;
524
 
525
    char pcPrefix = 'c';
526
    for (int i = 0; i < fdefBuffer.length; i++)
527
    {
528
      if (fdefBuffer[i] == inst)
529
      {
530
        pcPrefix = 'f';
531
        break;
532
      }
533
    }
534
    sbuf.append(pcPrefix);
535
 
536
 
537
    sbuf.append(getHex((short) inst.position()));
538
    sbuf.append(": ");
539
    sbuf.append(getHex((byte) bcode));
540
    sbuf.append("  ");
541
    sbuf.append(INST_NAME[bcode]);
542
 
543
    if (bcode == 0x40) // NPUSHB
544
    {
545
      count = inst.get(pc + 1) & 0xff;
546
      sbuf.append(" (");
547
      sbuf.append(count);
548
      sbuf.append(") ");
549
      for (int i = 0; i < count; i++)
550
      {
551
        if (i > 0)
552
          sbuf.append(" ");
553
        sbuf.append('$');
554
        sbuf.append(getHex(inst.get(pc + 2 + i)));
555
      }
556
    }
557
    if (bcode == 0x41) // NPUSHW
558
    {
559
      count = inst.get(pc + 1) & 0xff;
560
      sbuf.append(" (");
561
      sbuf.append(count);
562
      sbuf.append(") ");
563
      for (int i = 0; i < count; i++)
564
      {
565
        if (i > 0)
566
          sbuf.append(' ');
567
        sbuf.append('$');
568
        sbuf.append(getHex(inst.getShort(pc + 2 + 2*i)));
569
      }
570
    }
571
    else
572
    {
573
      count = getInstructionLength(bcode) - 1;
574
      for (int i = 0; i < count; i++)
575
      {
576
        sbuf.append(" $");
577
        sbuf.append(getHex(inst.get(pc + 1 + i)));
578
      }
579
    }
580
 
581
    while (sbuf.length() < 30)
582
      sbuf.append(' ');
583
    sbuf.append('|');
584
    sbuf.append(sp + 1);
585
    sbuf.append("| ");
586
    for (int i = sp; i >= Math.max(0, sp - 5); i = i - 1)
587
    {
588
      if (i < sp)
589
        sbuf.append(" ");
590
      if ((stack[i] >> 16) != 0)
591
        sbuf.append(getHex((short) (stack[i] >> 16)));
592
      sbuf.append(getHex((short) stack[i]));
593
    }
594
    System.out.println(sbuf);
595
  }
596
 
597
 
598
  private static char getNibble(int i, int rightShift)
599
  {
600
    i = (i >> rightShift) & 15;
601
    if (i < 10)
602
      return (char) (i + '0');
603
    else
604
      return (char) (i + 'a' - 10);
605
  }
606
 
607
 
608
  private static String getHex(byte b)
609
  {
610
    char[] a = new char[2];
611
    a[0] = getNibble(b, 4);
612
    a[1] = getNibble(b, 0);
613
    return new String(a);
614
  }
615
 
616
 
617
  private static String getHex(short b)
618
  {
619
    char[] a = new char[4];
620
    a[0] = getNibble(b, 12);
621
    a[1] = getNibble(b, 8);
622
    a[2] = getNibble(b, 4);
623
    a[3] = getNibble(b, 0);
624
    return new String(a);
625
  }
626
 
627
 
628
  /**
629
   * Skips any instructions until the specified opcode has been
630
   * encoutered.
631
   *
632
   * @param inst the current instruction stream. After the call,
633
   * the position of <code>inst</code> is right after the first
634
   * occurence of <code>opcode</code>.
635
   *
636
   * @param opcode1 the opcode for which to look.
637
   *
638
   * @param opcode2 another opcode for which to look. Pass -1
639
   * if only <code>opcode1</code> would terminate skipping.
640
   *
641
   * @param illegalCode1 an opcode that must not be encountered
642
   * while skipping. Pass -1 if any opcode is acceptable.
643
   *
644
   * @param illegalCode2 another opcode that must not be encountered
645
   * while skipping. Pass -1 to perform no check.
646
   *
647
   * @param handleNestedIfClauses <code>true</code> to handle
648
   * nested <code>IF [ELSE] EIF</code> clauses, <code>false</code>
649
   * to ignore them. From the TrueType specification document,
650
   * one would think that nested if clauses would not be valid,
651
   * but they do appear in some fonts.
652
   *
653
   * @throws IllegalStateException if <code>illegalCode1</code> or
654
   * <code>illegalCode2</code> has been encountered while skipping.
655
   */
656
  private static void skipAfter(ByteBuffer inst,
657
                                int opcode1, int opcode2,
658
                                int illegalCode1, int illegalCode2,
659
                                boolean handleNestedIfClauses)
660
  {
661
    int pos = inst.position();
662
    int curOpcode;
663
    int instLen;
664
    int nestingLevel = 0; // increased inside IF [ELSE] EIF sequences
665
 
666
    while (true)
667
    {
668
      curOpcode = inst.get(pos) & 0xff;
669
      instLen = getInstructionLength(curOpcode);
670
 
671
      if (false && TRACE_EXECUTION)
672
      {
673
        for (int i = 0; i < nestingLevel; i++)
674
          System.out.print("--");
675
        System.out.print("--" + pos + "-" + INST_NAME[curOpcode]);
676
        if (nestingLevel > 0)
677
          System.out.print(", ifNestingLevel=" + nestingLevel);
678
        System.out.println();
679
      }
680
 
681
      if (curOpcode == 0x40) // NPUSHB
682
        pos += 1 + (inst.get(pos + 1) & 0xff);
683
      else if (curOpcode == 0x41) // NPUSHW
684
        pos += 1 + 2 * (inst.get(pos + 1) & 0xff);
685
      else
686
        pos += instLen;
687
 
688
      if ((nestingLevel == 0)
689
          && ((curOpcode == opcode1) || (curOpcode == opcode2)))
690
        break;
691
 
692
      if (handleNestedIfClauses)
693
      {
694
        if (curOpcode == /* IF */ 0x58)
695
          ++nestingLevel;
696
        else if (curOpcode == /* EIF */ 0x59)
697
          --nestingLevel;
698
      }
699
 
700
      if ((nestingLevel < 0)
701
          || (curOpcode == illegalCode1)
702
          || (curOpcode == illegalCode2))
703
        throw new IllegalStateException();
704
    }
705
 
706
    inst.position(pos);
707
  }
708
 
709
 
710
  /**
711
   * Returns the number of bytes that a TrueType instruction occupies.
712
   *
713
   * @param opcode the instruction.
714
   *
715
   * @return the number of bytes occupied by the instructions and its
716
   * operands. For <code>NPUSHB</code> and <code>NPUSHW</code>, where
717
   * the instruction length depends on the first operand byte, the
718
   * result is -1.
719
   */
720
  private static int getInstructionLength(int opcode)
721
  {
722
    /* NPUSHB, NPUSHW --> see following byte */
723
    if ((opcode == 0x40) || (opcode == 0x41))
724
      return -1;
725
 
726
    /* PUSHB[0] .. PUSHB[7] --> 2, 3, 4, 5, 6, 7, 8, 9 */
727
    if ((opcode >= 0xb0) && (opcode <= 0xb7))
728
      return opcode - 0xae;
729
 
730
    /* PUSHW[0] .. PUSHW[7] --> 3, 5, 6, 7, 11, 13, 15, 17*/
731
    if ((opcode >= 0xb8) && (opcode <= 0xbf))
732
      return 1 + ((opcode - 0xb7) << 1);
733
 
734
    return 1;
735
  }
736
 
737
 
738
  /**
739
   * Executes a single TrueType instruction. This is the core
740
   * routine of the Virtual Machine.
741
   *
742
   * @return <code>true</code> if another instruction shall be
743
   * executed in the same call frame; <code>false</code> if the
744
   * current call frame shall be popped.
745
   */
746
  private boolean executeInstruction(ByteBuffer inst)
747
  {
748
    if (TRACE_EXECUTION)
749
      dumpInstruction(inst);
750
 
751
    int i, count, e1, e2, e3, e4, x, y;
752
    int bcode = inst.get() & 0xff;
753
 
754
    switch (bcode)
755
    {
756
    case 0x00: // SVTCA[0], Set freedom and proj. Vectors To Coord. Axis [y]
757
      setFreedomVector((short) 0, ONE_214);
758
      setProjectionVector((short) 0, ONE_214);
759
      break;
760
 
761
    case 0x01: // SVTCA[1], Set freedom and proj. Vectors To Coord. Axis [x]
762
      setFreedomVector(ONE_214, (short) 0);
763
      setProjectionVector(ONE_214, (short) 0);
764
      break;
765
 
766
    case 0x02: // SPVTCA[0], Set Projection Vector To Coordinate Axis [y]
767
      setProjectionVector((short) 0, ONE_214);
768
      break;
769
 
770
    case 0x03: // SPVTCA[1], Set Projection Vector To Coordinate Axis [x]
771
      setProjectionVector(ONE_214, (short) 0);
772
      break;
773
 
774
    case 0x0c: // GPV, Get Projection Vector
775
      stack[++sp] = projX;
776
      stack[++sp] = projY;
777
      break;
778
 
779
    case 0x0d: // GPV, Get Freedom Vector
780
      stack[++sp] = freeX;
781
      stack[++sp] = freeY;
782
      break;
783
 
784
    case 0x0F: // ISECT, move point p to the InterSECTION of two lines
785
      sp -= 4;
786
      handleISECT(stack[sp], stack[sp+1], stack[sp+2],
787
                  stack[sp+3], stack[sp+4]);
788
      break;
789
 
790
    case 0x10: // SRP0, Set Reference Point 0
791
      rp0 = stack[sp--];
792
      break;
793
 
794
    case 0x11: // SRP1, Set Reference Point 1
795
      rp1 = stack[sp--];
796
      break;
797
 
798
    case 0x12: // SRP2, Set Reference Point 2
799
      rp2 = stack[sp--];
800
      break;
801
 
802
    case 0x13: // SZP0, Set Zone Pointer 0
803
      zp0 = getZone(stack[sp--]);
804
      break;
805
 
806
    case 0x14: // SZP1, Set Zone Pointer 1
807
      zp1 = getZone(stack[sp--]);
808
      break;
809
 
810
    case 0x15: // SZP2, Set Zone Pointer 2
811
      zp2 = getZone(stack[sp--]);
812
      break;
813
 
814
    case 0x16: // SZPS, Set Zone PointerS
815
      zp0 = zp1 = zp2 = getZone(stack[sp--]);
816
      break;
817
 
818
    case 0x17: // SLOOP, Set LOOP variable
819
      loop = stack[sp--];
820
      break;
821
 
822
    case 0x18: // RTG, Round To Grid
823
      setRoundingMode(Fixed.ONE, 0x48);
824
      break;
825
 
826
    case 0x19: // RTHG, Round To Half Grid
827
      setRoundingMode(Fixed.ONE, 0x68);
828
      break;
829
 
830
    case 0x1a: // SMD, Set Minimum Distance
831
      minimumDistance = stack[sp--];
832
      break;
833
 
834
    case 0x1B: // ELSE, ELSE clause
835
      skipAfter(inst,
836
                /* look for: EIF, -- */ 0x59, -1,
837
                /* illegal: --, -- */   -1, -1,
838
                /* handle nested if clauses */ true);
839
      break;
840
 
841
    case 0x1C: // JMPR, JuMP Relative
842
      inst.position(inst.position() - 1 + stack[sp--]);
843
      break;
844
 
845
    case 0x1D: // SCVTCI, Set Control Value Table Cut-In
846
      cvtCutIn = stack[sp--];
847
      break;
848
 
849
    case 0x1F: // SSW, Set Single Width
850
      singleWidthValue = stack[sp--];
851
      break;
852
 
853
    case 0x20: // DUP, DUPlicate top stack element
854
      e1 = stack[sp];
855
      stack[++sp] = e1;
856
      break;
857
 
858
    case 0x21: // POP, POP top stack element
859
      sp--;
860
      break;
861
 
862
    case 0x22: // CLEAR, CLEAR the stack
863
      sp = -1;
864
      break;
865
 
866
    case 0x23: // SWAP, SWAP the top two elements on the stack
867
      e1 = stack[sp--];
868
      e2 = stack[sp];
869
      stack[sp] = e1;
870
      stack[++sp] = e2;
871
      break;
872
 
873
    case 0x24: // DEPTH, DEPTH of the stack
874
      stack[++sp] = sp + 1;
875
      break;
876
 
877
    case 0x25: // CINDEX, Copy the INDEXed element to the top of the stack
878
      stack[sp] = stack[sp - stack[sp]];
879
      break;
880
 
881
    case 0x26: // MINDEX, Move the INDEXed element to the top of the stack
882
      i = stack[sp];
883
      e1 = stack[sp - i];
884
      System.arraycopy(/* src */ stack,  /* srcPos */ sp - i + 1,
885
                       /* dest */ stack, /* destPos*/ sp - i,
886
                       /* length */ i - 1);
887
      --sp;
888
      stack[sp] = e1;
889
      break;
890
 
891
    case 0x2a: // LOOPCALL, LOOP and CALL function
892
      i = stack[sp--];
893
      count = stack[sp--];
894
      e1 = inst.position();
895
      e2 = sp;
896
      for (int j = 0; j < count; j++)
897
        execute(fdefBuffer[i], fdefEntryPoint[i]);
898
      inst.position(e1);
899
      break;
900
 
901
    case 0x2B: // CALL, CALL function
902
      i = stack[sp--];
903
      e1 = inst.position();
904
      e2 = sp;
905
      execute(fdefBuffer[i], fdefEntryPoint[i]);
906
      inst.position(e1);
907
      break;
908
 
909
    case 0x2C: // FDEF, Function DEFinition
910
      i = stack[sp--];
911
      fdefBuffer[i] = inst;
912
      fdefEntryPoint[i] = inst.position();
913
      skipAfter(inst,
914
                /* look for: ENDF */ 0x2d,
915
                /* look for: --- */ -1,
916
                /* illegal: IDEF */ 0x89,
917
                /* illegal: FDEF */ 0x2c,
918
                /* do not handle nested if clauses */ false);
919
      break;
920
 
921
    case 0x2D: // ENDF, END Function definition
922
      /* Pop the current stack frame. */
923
      return false;
924
 
925
    case 0x2e: // MDAP[0], Move Direct Absolute Point
926
      handleMDAP(stack[sp--], /* round */ false);
927
      break;
928
 
929
    case 0x2f: // MDAP[1], Move Direct Absolute Point
930
      handleMDAP(stack[sp--], /* round */ true);
931
      break;
932
 
933
    case 0x39: // IP, Interpolate Point by the last relative stretch
934
      handleIP();
935
      break;
936
 
937
    case 0x3d: // RTDG, Round To Double Grid
938
      setRoundingMode(Fixed.ONE, 0x08);
939
      roundThreshold = roundThreshold / 64; // period/128
940
      break;
941
 
942
    case 0x3e: // MIAP[0], Move Indirect Absolute Point
943
      e1 = stack[sp--];
944
      handleMIAP(e1, stack[sp--], /* round */ false);
945
      break;
946
 
947
    case 0x3f: // MIAP[1], Move Indirect Absolute Point
948
      e1 = stack[sp--];
949
      handleMIAP(e1, stack[sp--], /* round */ true);
950
      break;
951
 
952
    case 0x40: // NPUSHB
953
      count = inst.get() & 0xff;
954
      for (i = 0; i < count; i++)
955
        stack[++sp] = inst.get() & 0xff;
956
      break;
957
 
958
    case 0x41: // NPUSHW
959
      count = inst.get() & 0xff;
960
      for (i = 0; i < count; i++)
961
        stack[++sp] = inst.getShort();
962
      break;
963
 
964
    case 0x42: // WS, Write Store
965
      e1 = stack[sp--]; i = stack[sp--];
966
      storage[i] = e1;
967
      break;
968
 
969
    case 0x43: // RS, Read Store
970
      stack[sp] = storage[stack[sp]];
971
      break;
972
 
973
    case 0x44: // WCVTP, Write Control Value Table in Pixel units
974
      e1 = stack[sp--];
975
      i = stack[sp--];
976
      if (i < cvt.length)
977
        cvt[i] = e1;
978
      break;
979
 
980
    case 0x45: // RCVT, Read Control Value Table entry
981
      if (stack[sp] < cvt.length)
982
        stack[sp] = cvt[stack[sp]];
983
      else
984
        stack[sp] = 0;
985
      break;
986
 
987
    case 0x46: // GC[0], Get Coordinate projected onto the projection vector
988
      stack[sp] = getProjection(zp2, stack[sp]);
989
      break;
990
 
991
    case 0x47: // GC[1], Get Coordinate projected onto the projection vector
992
      stack[sp] = getOriginalProjection(zp2, stack[sp]);
993
      break;
994
 
995
    case 0x4B: // MPPEM, Measure Pixels Per EM
996
      stack[++sp] = getPixelsPerEM();
997
      break;
998
 
999
    case 0x4c: // MPS, Measure Point Size
1000
      /* FreeType2 returns pixels per em here, because they think that
1001
       * the point size would be irrelevant in a given font program.
1002
       * This is extremely surprising, because the appearance of good
1003
       * fonts _should_ change with point size. For example, a good
1004
       * font should be wider at small point sizes, and the holes
1005
       * inside glyphs ("Punzen" in German, I do not know the correct
1006
       * English expression) should be larger. Note that this change
1007
       * of appearance is dependent on point size, _not_ the
1008
       * resolution of the display device.
1009
       */
1010
      stack[++sp] = pointSize;
1011
      break;
1012
 
1013
    case 0x4f: // DEBUG, DEBUG call
1014
      sp--;
1015
      break;
1016
 
1017
    case 0x50: // LT, Less Than
1018
      e1 = stack[sp--];
1019
      stack[sp] = (stack[sp] < e1) ? 1 : 0;
1020
      break;
1021
 
1022
    case 0x51: // LTEQ, Greater Than or EQual
1023
      e1 = stack[sp--];
1024
      stack[sp] = (stack[sp] <= e1) ? 1 : 0;
1025
      break;
1026
 
1027
    case 0x52: // GT, Greater Than
1028
      e1 = stack[sp--];
1029
      stack[sp] = (stack[sp] > e1) ? 1 : 0;
1030
      break;
1031
 
1032
    case 0x53: // GTEQ, Greater Than or EQual
1033
      e1 = stack[sp--];
1034
      stack[sp] = (stack[sp] >= e1) ? 1 : 0;
1035
      break;
1036
 
1037
    case 0x54: // EQ, EQual
1038
      e1 = stack[sp--];
1039
      stack[sp] = (stack[sp] == e1) ? 1 : 0;
1040
      break;
1041
 
1042
    case 0x55: // NEQ, Not EQual
1043
      e1 = stack[sp--];
1044
      stack[sp] = (stack[sp] != e1) ? 1 : 0;
1045
      break;
1046
 
1047
    case 0x58: // IF, IF test
1048
      if (stack[sp--] == 0)
1049
        skipAfter(inst,
1050
                  /* look for: ELSE */ 0x1B,
1051
                  /* look for: EIF */  0x59,
1052
                  /* illegal: -- */    -1,
1053
                  /* illegal: -- */    -1,
1054
                  /* handle nested if clauses */ true);
1055
      break;
1056
 
1057
    case 0x59: // EIF, End IF
1058
      // Do nothing.
1059
      break;
1060
 
1061
    case 0x5A: // AND
1062
      e1 = stack[sp--];
1063
      stack[sp] = ((e1 != 0) && (stack[sp] != 0)) ? 1 : 0;
1064
      break;
1065
 
1066
    case 0x5B: // OR
1067
      e1 = stack[sp--];
1068
      stack[sp] = ((e1 != 0) || (stack[sp] != 0)) ? 1 : 0;
1069
      break;
1070
 
1071
    case 0x5C: // NOT
1072
      stack[sp] = (stack[sp] != 0) ? 0 : 1;
1073
      break;
1074
 
1075
    case 0x5e: // SDB, Set Delta Base in the graphics state
1076
      deltaBase = stack[sp--];
1077
      break;
1078
 
1079
    case 0x5f: // SDS, Set Delta Shift in the graphics state
1080
      deltaShift = stack[sp--];
1081
      break;
1082
 
1083
    case 0x60: // ADD
1084
      e1 = stack[sp--];
1085
      stack[sp] += e1;
1086
      break;
1087
 
1088
    case 0x61: // SUB, SUBtract
1089
      e1 = stack[sp--];
1090
      stack[sp] -= e1;
1091
      break;
1092
 
1093
    case 0x62: // DIV, DIVide
1094
      e1 = stack[sp--];
1095
      stack[sp] = Fixed.div(e1, stack[sp]);
1096
      break;
1097
 
1098
    case 0x63:  // MUL, MULtiply
1099
      e1 = stack[sp--];
1100
      stack[sp] = Fixed.mul(e1, stack[sp]);
1101
      break;
1102
 
1103
    case 0x64: // ABS, ABSolute value
1104
      stack[sp] = Math.abs(stack[sp]);
1105
      break;
1106
 
1107
    case 0x65: // NEG, NEGate
1108
      stack[sp] = -stack[sp];
1109
      break;
1110
 
1111
    case 0x66: // FLOOR
1112
      stack[sp] = Fixed.floor(stack[sp]);
1113
      break;
1114
 
1115
    case 0x67: // CEILING
1116
      stack[sp] = Fixed.ceil(stack[sp]);
1117
      break;
1118
 
1119
    case 0x68: // ROUND[0] -- round grey distance
1120
      stack[sp] = round(stack[sp], /* no engine compensation */ 0);
1121
      break;
1122
 
1123
    case 0x69: // ROUND[1] -- round black distance
1124
      stack[sp] = round(stack[sp], -engineCompensation);
1125
      break;
1126
 
1127
    case 0x6a: // ROUND[2] -- round white distance
1128
      stack[sp] = round(stack[sp], engineCompensation);
1129
      break;
1130
 
1131
    case 0x6b: // ROUND[3] -- round distance (not yet defined)
1132
      stack[sp] = round(stack[sp], /* no engine compensation */ 0);
1133
      break;
1134
 
1135
    case 0x6c: // NROUND[0] -- compensate grey distance
1136
      stack[sp] = nround(stack[sp], 0);
1137
      break;
1138
 
1139
    case 0x6d: // NROUND[1] -- compensate black distance
1140
      stack[sp] = nround(stack[sp], -engineCompensation);
1141
      break;
1142
 
1143
    case 0x6e: // NROUND[2] -- compensate white distance
1144
      stack[sp] = nround(stack[sp], engineCompensation);
1145
      break;
1146
 
1147
    case 0x6f: // NROUND[3] -- compensate distance (not yet defined)
1148
      stack[sp] = nround(stack[sp], 0);
1149
      break;
1150
 
1151
    case 0x70: // WCVTF, Write Control Value Table in Funits
1152
      e1 = stack[sp--];
1153
      cvt[stack[sp--]] = e1 * getPixelsPerEM();
1154
      break;
1155
 
1156
    case 0x73: // DELTAC1, DELTA exception C1
1157
      count = stack[sp--];
1158
      sp -= 2 * count;
1159
      deltaC(stack, sp + 1, count, 0);
1160
      break;
1161
 
1162
    case 0x74: // DELTAC2, DELTA exception C2
1163
      count = stack[sp--];
1164
      sp -= 2 * count;
1165
      deltaC(stack, sp + 1, count, 16);
1166
      break;
1167
 
1168
    case 0x75: // DELTAC3, DELTA exception C3
1169
      count = stack[sp--];
1170
      sp -= 2 * count;
1171
      deltaC(stack, sp + 1, count, 32);
1172
      break;
1173
 
1174
    case 0x76: // SROUND, Super ROUND
1175
      setRoundingMode(Fixed.ONE, stack[sp--]);
1176
      break;
1177
 
1178
    case 0x77: // S45ROUND, Super ROUND 45 degrees
1179
      setRoundingMode(/* sqrt(2)/2 */ 0x2d, stack[sp--]);
1180
      break;
1181
 
1182
    case 0x78: // JROT, Jump Relative On True
1183
      e1 = stack[sp--];
1184
      i = inst.position() - 1 + stack[sp--];
1185
      if (e1 != 0)
1186
        inst.position(i);
1187
      break;
1188
 
1189
    case 0x79: // JROF, Jump Relative On False
1190
      e1 = stack[sp--];
1191
      i = inst.position() - 1 + stack[sp--];
1192
      if (e1 == 0)
1193
        inst.position(i);
1194
      break;
1195
 
1196
    case 0x7a: // ROFF, Round OFF
1197
      roundPeriod = 0;
1198
      break;
1199
 
1200
    case 0x7c: // RUTG, Round Up To Grid
1201
      setRoundingMode(Fixed.ONE, 0x40);
1202
      break;
1203
 
1204
    case 0x7d: // RDTG, Round Down To Grid
1205
      setRoundingMode(Fixed.ONE, 0x40);
1206
      roundThreshold = 0;
1207
      break;
1208
 
1209
    case 0x7e: // SANGW, Set ANGle Weight (no-op according to TrueType spec)
1210
    case 0x7f: // AA, Adjust Angle (no-op according to TrueType spec)
1211
      sp--;
1212
      break;
1213
 
1214
    case 0x85: // SCANCTRL, SCAN conversion ConTRoL
1215
      e1 = stack[sp--];
1216
      int ppemThreshold = e1 & 255;
1217
      scanControl = false;
1218
      boolean ppemCondition = (ppemThreshold == 255)
1219
        || ((ppemThreshold != 0) && (getPixelsPerEM() > ppemThreshold));
1220
      if (((e1 & (1<<8)) != 0) && ppemCondition)
1221
        scanControl = true;
1222
      if (((e1 & (1<<9)) != 0) && isRotated())
1223
        scanControl = true;
1224
      if (((e1 & (1<<10)) != 0) && isStretched())
1225
        scanControl = true;
1226
      if (((e1 & (1<<11)) != 0) && !ppemCondition)
1227
        scanControl = false;
1228
      if (((e1 & (1<<12)) != 0) && !isRotated())
1229
        scanControl = false;
1230
      if (((e1 & (1<<13)) != 0) && !isStretched())
1231
        scanControl = false;
1232
      break;
1233
 
1234
    case 0x88: // GETINFO, GET INFOrmation
1235
      e1 = 0;
1236
      if ((stack[sp] & 1) != 0) // ask for rasterizer version
1237
        e1 |= 35; // "Microsoft Rasterizer version 1.7" (grayscale-capable)
1238
      if (((stack[sp] & 2) != 0) && isRotated())
1239
        e1 |= 1 << 8; // bit 8: glyph has been rotated
1240
      if (((stack[sp] & 4) != 0) && isStretched())
1241
        e1 |= 1 << 9; // bit 9: glyph has been stretched
1242
      if (((stack[sp] & 32) != 0) && antialiased)
1243
        e1 |= 1 << 12; // bit 12: antialiasing is active
1244
      stack[sp] = e1;
1245
      break;
1246
 
1247
    case 0x8a: // ROLL, ROLL the top three stack elements
1248
      e1 = stack[sp - 2];
1249
      stack[sp - 2] = stack[sp - 1];
1250
      stack[sp - 1] = stack[sp];
1251
      stack[sp] = e1;
1252
      break;
1253
 
1254
    case 0x8b: // MAX, MAXimum of top two stack elements
1255
      e1 = stack[sp--];
1256
      stack[sp] = Math.max(e1, stack[sp]);
1257
      break;
1258
 
1259
    case 0x8c: // MIN, MINimum of top two stack elements
1260
      e1 = stack[sp--];
1261
      stack[sp] = Math.min(e1, stack[sp]);
1262
      break;
1263
 
1264
    case 0x8d: // SCANTYPE
1265
      scanType = stack[sp--];
1266
      break;
1267
 
1268
    case 0x8e: // INSTCTRL, INSTRuction execution ConTRoL
1269
      e1 = stack[sp--]; // selector
1270
      e2 = stack[sp--]; // value
1271
      switch (e1)
1272
      {
1273
      case 1:
1274
        executeGlyphInstructions = (e2 == 0);
1275
        break;
1276
 
1277
      case 2:
1278
        ignoreCVTProgram = (e2 != 0);
1279
        break;
1280
      }
1281
      break;
1282
 
1283
    case 0xb0: // PUSHB[0]
1284
    case 0xb1: // PUSHB[1]
1285
    case 0xb2: // PUSHB[2]
1286
    case 0xb3: // PUSHB[3]
1287
    case 0xb4: // PUSHB[4]
1288
    case 0xb5: // PUSHB[5]
1289
    case 0xb6: // PUSHB[6]
1290
    case 0xb7: // PUSHB[7]
1291
      count = bcode - 0xb0 + 1;
1292
      for (i = 0; i < count; i++)
1293
        stack[++sp] = inst.get() & 0xff;
1294
      break;
1295
 
1296
    case 0xb8: // PUSHW[0]
1297
    case 0xb9: // PUSHW[1]
1298
    case 0xba: // PUSHW[2]
1299
    case 0xbb: // PUSHW[3]
1300
    case 0xbc: // PUSHW[4]
1301
    case 0xbd: // PUSHW[5]
1302
    case 0xbe: // PUSHW[6]
1303
    case 0xbf: // PUSHW[7]
1304
      count = bcode - 0xb8 + 1;
1305
      for (i = 0; i < count; i++)
1306
        stack[++sp] = inst.getShort();
1307
      break;
1308
 
1309
      // MIRPxxxx, Move Indirect Relative Point
1310
    case 0xe0: case 0xe1: case 0xe2: case 0xe3:
1311
    case 0xe4: case 0xe5: case 0xe6: case 0xe7:
1312
    case 0xe8: case 0xe9: case 0xea: case 0xeb:
1313
    case 0xec: case 0xed: case 0xee: case 0xef:
1314
    case 0xf0: case 0xf1: case 0xf2: case 0xf3:
1315
    case 0xf4: case 0xf5: case 0xf6: case 0xf7:
1316
    case 0xf8: case 0xf9: case 0xfa: case 0xfb:
1317
    case 0xfc: case 0xfd: case 0xfe: case 0xff:
1318
      e1 = stack[sp--];
1319
      handleMIRP(bcode, /* point */ e1, /* cvtIndex */ stack[sp--]);
1320
      break;
1321
 
1322
    default:
1323
      throw new IllegalStateException();
1324
    }
1325
 
1326
    return true;
1327
  }
1328
 
1329
 
1330
  /**
1331
   * Sets the rounding mode.
1332
   *
1333
   * @param period the grid period in fixed-point notation, such as
1334
   * {@link Fixed#ONE} for the <code>SROUND</code> instruction or
1335
   * <code>sqrt(2)/2</code> for the <code>S45ROUND</code> instruction.
1336
   *
1337
   * @param mode a byte whose bits are set according to the TrueType
1338
   * specification for SROUND and S45ROUND parameters.
1339
   */
1340
  private void setRoundingMode(int period, int mode)
1341
  {
1342
    /* Set the period. */
1343
    switch ((mode & 0xc0) >> 6)
1344
    {
1345
    case 0:
1346
      roundPeriod = period / 2;
1347
      break;
1348
 
1349
    case 2:
1350
      roundPeriod = period * 2;
1351
      break;
1352
 
1353
    default:
1354
      roundPeriod = period;
1355
      break;
1356
    }
1357
 
1358
    /* Set the phase. */
1359
    switch ((mode & 0x30) >> 4)
1360
    {
1361
    case 0:
1362
      roundPhase = 0;
1363
      break;
1364
 
1365
    case 1:
1366
      roundPhase = roundPeriod >> 2;  // period/4
1367
      break;
1368
 
1369
    case 2:
1370
      roundPhase = roundPeriod >> 1; // period/2
1371
      break;
1372
 
1373
    case 3:
1374
      roundPhase = (roundPeriod >> 1) + (roundPeriod >> 2); // period * 3/4
1375
      break;
1376
    }
1377
 
1378
    /* Set the threshold. */
1379
    int threshold = mode & 0x0f;
1380
    if (threshold == 0)
1381
      roundThreshold = roundPeriod - Fixed.ONE;
1382
    else
1383
      roundThreshold = ((threshold - 4) * roundPeriod) / 8;
1384
  }
1385
 
1386
 
1387
 
1388
  /**
1389
   * Implements the DELTAC instructions. These instructions check
1390
   * whether the current number of pixels per em is contained in an
1391
   * exception table.  If it is, a delta value is determined, and the
1392
   * specified entry in the Control Value Table is modified according
1393
   * to the delta.
1394
   *
1395
   * @param pairs the delta table. Because the delta table is on
1396
   * the stack, callers usually just want to pass the stack array.
1397
   *
1398
   * @param offset the offset of the first pair in <code>pairs</code>.
1399
   *
1400
   * @param numPairs the number of pairs.
1401
   *
1402
   * @param base 0 for <code>DELTAC1</code>, 16 for <code>DELTAC2</code>,
1403
   * or 32 for <code>DELTAC2</code>.
1404
   *
1405
   * @see <a href=
1406
   * "http://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#DELTAC1"
1407
   * >Apple&#x2019;s documentation for <code>DELTAC1</code></a>, <a href=
1408
   * "http://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#DELTAC2"
1409
   * ><code>DELTAC2</code></a>, and <a href=
1410
   * "http://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#DELTAC3"
1411
   * ><code>DELTAC3</code></a>
1412
   */
1413
  private void deltaC(int[] pairs, int offset, int numPairs, int base)
1414
  {
1415
    int arg, relativePpem;
1416
    int ppemTrigger = getPixelsPerEM() - (deltaBase + base);
1417
    int delta, cvtIndex, rightShift;
1418
    for (int i = 0; i < numPairs; i++)
1419
    {
1420
      arg = pairs[offset + 2 * i];
1421
      relativePpem = (arg >> 4) & 15;
1422
      if (relativePpem == ppemTrigger)
1423
      {
1424
        delta = (arg & 15) - 8;
1425
        if (delta >= 0)
1426
          ++delta;
1427
 
1428
        rightShift = deltaShift - 6;
1429
        if (rightShift > 0)
1430
          delta = delta >> rightShift;
1431
        else if (rightShift < 0)
1432
          delta = delta << (-rightShift);
1433
        cvt[pairs[offset + 2 * i + 1]] += delta;
1434
 
1435
        break;
1436
      }
1437
    }
1438
  }
1439
 
1440
 
1441
  private Zone getZone(int zoneNumber)
1442
  {
1443
    return (zoneNumber == 0) ? twilightZone : glyphZone;
1444
  }
1445
 
1446
 
1447
  /**
1448
   * Projects the specified vector along the current projection
1449
   * vector.
1450
   *
1451
   * @param x the x component of the input vector, in 26.6 fixed-point
1452
   * notation.
1453
   *
1454
   * @param y the y component of the input vector, in 26.6 fixed-point
1455
   * notation.
1456
   *
1457
   * @return the projected distance, in 26.6 fixed-point notation.
1458
   */
1459
  private int getProjection(int x, int y)
1460
  {
1461
    return (int) (((((long) x) * projX + ((long) y) * projY)) >> 14);
1462
  }
1463
 
1464
 
1465
  /**
1466
   * Projects the specified vector along the current dual projection
1467
   * vector.
1468
   *
1469
   * @param x the x component of the input vector, in 26.6 fixed-point
1470
   * notation.
1471
   *
1472
   * @param y the y component of the input vector, in 26.6 fixed-point
1473
   * notation.
1474
   *
1475
   * @return the projected distance, in 26.6 fixed-point notation.
1476
   */
1477
  private int getDualProjection(int x, int y)
1478
  {
1479
    return (int) (((((long) x) * dualX + ((long) y) * dualY)) >> 14);
1480
  }
1481
 
1482
 
1483
  private int getProjection(Zone zone, int point)
1484
  {
1485
    return getProjection(zone.getX(point), zone.getY(point));
1486
  }
1487
 
1488
 
1489
  private int getOriginalProjection(Zone zone, int point)
1490
  {
1491
    return getDualProjection(zone.getOriginalX(point),
1492
                             zone.getOriginalY(point));
1493
  }
1494
 
1495
 
1496
  private void handleISECT(int a0, int a1, int b0, int b1, int p)
1497
  {
1498
    System.out.println("FIXME: Unimplemented ISECT " + p);
1499
  }
1500
 
1501
 
1502
  private static int muldiv(int a, int b, int c)
1503
  {
1504
    int s;
1505
    s = a; a = Math.abs(a);
1506
    s ^= b; b = Math.abs(b);
1507
    s ^= c; c = Math.abs(c);
1508
    a = (int) ((((long) a) * b + (c>>1)) / c);
1509
    return (s < 0) ? -a : a;
1510
  }
1511
 
1512
 
1513
  private int getFreeDotProj()
1514
  {
1515
    int result;
1516
 
1517
    result = ((((int) projX) * freeX) << 2)
1518
      + ((((int) projY) * freeY) << 2);
1519
 
1520
    /* FIXME: This seems somewhat bogus. Need to contact the
1521
     * developers of FreeType.
1522
     */
1523
    if (Math.abs(result) < 0x4000000)
1524
      result = 0x40000000;
1525
    return result;
1526
  }
1527
 
1528
 
1529
  private void movePoint(Zone zone, int point, int distance)
1530
  {
1531
    int freeDotProj = getFreeDotProj();
1532
    int c;
1533
 
1534
    if (freeX != 0)
1535
    {
1536
      c = zone.getX(point);
1537
      c += muldiv(distance, freeX << 16, freeDotProj);
1538
      zone.setX(point, c, /* touch */ true);
1539
    }
1540
 
1541
    if (freeY != 0)
1542
    {
1543
      c = zone.getY(point);
1544
      c += muldiv(distance, freeY << 16, freeDotProj);
1545
      zone.setY(point, c, /* touch */ true);
1546
    }
1547
 
1548
    if (TRACE_EXECUTION)
1549
    {
1550
      System.out.println("point[" + point + "] moved to "
1551
                         + Fixed.toString(zone.getX(point),
1552
                                          zone.getY(point)));
1553
      dumpVectors();
1554
    }
1555
  }
1556
 
1557
  private void dumpVectors()
1558
  {
1559
    System.out.println("  proj=" + Fixed.toString(projX>>8, projY>>8)
1560
                       + ", free=" + Fixed.toString(freeX>>8, freeY>>8));
1561
  }
1562
 
1563
 
1564
  private void handleIP()
1565
  {
1566
    // Implementation taken from FreeType.
1567
    int p, org_a, org_b, org_x, cur_a, cur_b, cur_x, distance;
1568
    int freeDotProj;
1569
 
1570
    org_a = getOriginalProjection(zp0, rp1);
1571
    cur_a = getProjection(zp0, rp1);
1572
 
1573
    org_b = getOriginalProjection(zp1, rp2);
1574
    cur_b = getProjection(zp1, rp2);
1575
 
1576
    while (--loop >= 0)
1577
    {
1578
      p = stack[sp--];
1579
      org_x = getOriginalProjection(zp2, p);
1580
      cur_x = getProjection(zp2, p);
1581
 
1582
      if (((org_a <= org_b) && (org_x <= org_a))
1583
          || ((org_a > org_b) && (org_x >= org_a)))
1584
        distance = (cur_a - org_a) + (org_x - cur_x);
1585
      else if (((org_a <= org_b) && (org_x >= org_b))
1586
               || ((org_a > org_b) && (org_x < org_b)))
1587
        distance = (cur_b - org_b) + (org_x - cur_x);
1588
      else
1589
        distance = muldiv(cur_b - cur_a, org_x - org_a, org_b - org_a)
1590
          + (cur_a - cur_x);
1591
      movePoint(zp2, p, distance);
1592
    }
1593
    loop = 1;
1594
  }
1595
 
1596
 
1597
  private void handleMDAP(int point, boolean round)
1598
  {
1599
    System.out.println("FIXME: Unimplemented MDAP: point "
1600
                       + point + "/" + zp0);
1601
  }
1602
 
1603
 
1604
  private void handleMIAP(int cvtIndex, int point, boolean round)
1605
  {
1606
    int previousPos, pos;
1607
 
1608
    previousPos = getProjection(zp0, point);
1609
    pos = cvt[cvtIndex];
1610
 
1611
    if (round)
1612
    {
1613
      if (Math.abs(pos - previousPos) > cvtCutIn)
1614
        pos = previousPos;
1615
      pos = round(pos, /* no engine compensation */ 0);
1616
    }
1617
    movePoint(zp0, point, pos - previousPos);
1618
    rp0 = rp1 = point;
1619
  }
1620
 
1621
 
1622
  private void handleMIRP(int bcode, int point, int cvtIndex)
1623
  {
1624
    System.out.println("FIXME: Unimplemented mirp " + point + ", " + cvtIndex);
1625
  }
1626
 
1627
 
1628
 
1629
  private int round(int distance, int compensation)
1630
  {
1631
    int result;
1632
 
1633
    if (roundPeriod == 0)
1634
      return nround(distance, compensation);
1635
 
1636
    if (distance >= 0)
1637
    {
1638
      result = distance + compensation - roundPhase + roundThreshold;
1639
      result &= -roundPeriod; // truncate to the next lowest periodic value
1640
      return Math.max(result, 0) + roundPhase;
1641
    }
1642
    else
1643
    {
1644
      result = compensation - roundPhase + roundThreshold - distance;
1645
      result &= -roundPeriod;
1646
      return Math.max(-result, 0) - roundPhase;
1647
    }
1648
  }
1649
 
1650
 
1651
  private static int nround(int distance, int compensation)
1652
  {
1653
    if (distance >= 0)
1654
      return Math.max(distance + compensation, 0);
1655
    else
1656
      return Math.min(distance - compensation, 0);
1657
  }
1658
 
1659
 
1660
  /**
1661
   * Determines whether the current glyph is rotated.
1662
   *
1663
   * @return <code>false</code> if the shearing factors for the
1664
   * <i>x</i> and <i>y</i> axes are zero; <code>true</code> if they
1665
   * are non-zero.
1666
   */
1667
  private boolean isRotated()
1668
  {
1669
    return (shearX != 0) || (shearY != 0);
1670
  }
1671
 
1672
 
1673
  /**
1674
   * Determines whether the current glyph is stretched.
1675
   *
1676
   * @return <code>false</code> if the scaling factors for the
1677
   * <i>x</i> and <i>y</i> axes are are equal; <code>true</code> if
1678
   * they differ.
1679
   */
1680
  private boolean isStretched()
1681
  {
1682
    return scaleX != scaleY;
1683
  }
1684
 
1685
 
1686
  /**
1687
   * Returns how many pixels there are per EM, in direction of the
1688
   * current projection vector. The result is a normal integer,
1689
   * not a Fixed.
1690
   */
1691
  private int getPixelsPerEM()
1692
  {
1693
    if (cachedPixelsPerEM == 0)
1694
    {
1695
      cachedPixelsPerEM = Fixed.intValue(Fixed.vectorLength(
1696
        applyCTM_x(projX >> 8, projY >> 8),
1697
        applyCTM_y(projX >> 8, projY >> 8)));
1698
    }
1699
 
1700
    return cachedPixelsPerEM;
1701
  }
1702
 
1703
 
1704
  private void setProjectionVector(short x, short y)
1705
  {
1706
    if (PATENTED_HINTING)
1707
    {
1708
      if ((x != projX) || (y != projY))
1709
        cachedPixelsPerEM = 0;
1710
 
1711
      projX = x;
1712
      projY = y;
1713
    }
1714
  }
1715
 
1716
 
1717
  private void setFreedomVector(short x, short y)
1718
  {
1719
    if (PATENTED_HINTING)
1720
    {
1721
      freeX = x;
1722
      freeY = y;
1723
    }
1724
  }
1725
 
1726
 
1727
  private void setDualVector(short x, short y)
1728
  {
1729
    if (PATENTED_HINTING)
1730
    {
1731
      dualX = x;
1732
      dualY = y;
1733
    }
1734
  }
1735
 
1736
 
1737
  private int applyCTM_x(int x, int y)
1738
  {
1739
    return (int) (((long) scaleX * x + (long) shearX * y) >> 6);
1740
  }
1741
 
1742
  private int applyCTM_y(int x, int y)
1743
  {
1744
    return (int) (((long) shearY * x + (long) scaleY * y) >> 6);
1745
  }
1746
 
1747
 
1748
  private static final String[] INST_NAME =
1749
  {
1750
    /* 00 */ "SVTCA[0]", "SVTCA[1]", "SPVTCA[0]", "SPVTCA[1]",
1751
    /* 04 */ "INST_04", "INST_05", "INST_06", "INST_07",
1752
    /* 08 */ "INST_08", "INST_09", "INST_0A", "INST_0B",
1753
    /* 0c */ "GPV", "GFV", "INST_0E", "ISECT",
1754
    /* 10 */ "SRP0", "SRP1", "SRP2", "SZP0",
1755
    /* 14 */ "SZP1", "SZP2", "SZPS", "SLOOP",
1756
    /* 18 */ "RTG", "RTHG", "SMD", "ELSE",
1757
    /* 1c */ "JMPR", "SCVTCI", "INST_1E", "SSW",
1758
    /* 20 */ "DUP", "POP", "CLEAR", "SWAP",
1759
    /* 24 */ "DEPTH", "CINDEX", "MINDEX", "INST_27",
1760
    /* 28 */ "INST_28", "INST_29", "LOOPCALL", "CALL",
1761
    /* 2c */ "FDEF", "ENDF", "MDAP[0]", "MDAP[1]",
1762
    /* 30 */ "IUP[0]", "IUP[1]", "SHP[0]", "SHP[1]",
1763
    /* 34 */ "INST_34", "INST_35", "INST_36", "INST_37",
1764
    /* 38 */ "INST_38", "IP", "INST_3A", "INST_3B",
1765
    /* 3c */ "INST_3C", "RTDG", "MIAP[0]", "MIAP[1]",
1766
    /* 40 */ "NPUSHB", "NPUSHW", "WS", "RS",
1767
    /* 44 */ "WCVTP", "RCVT", "GC[0]", "GC[1]",
1768
    /* 48 */ "INST_48", "INST_49", "INST_4A", "MPPEM",
1769
    /* 4c */ "MPS", "FLIPON", "FLIPOFF", "DEBUG",
1770
    /* 50 */ "LT", "LTEQ", "GT", "GTEQ",
1771
    /* 54 */ "EQ", "NEQ", "INST_56", "INST_57",
1772
    /* 58 */ "IF", "EIF", "AND", "OR",
1773
    /* 5c */ "NOT", "INST_5D", "SDB", "SDS",
1774
    /* 60 */ "ADD", "SUB", "DIV", "MUL",
1775
    /* 64 */ "ABS", "NEG", "FLOOR", "CEILING",
1776
    /* 68 */ "ROUND[0]", "ROUND[1]", "ROUND[2]", "ROUND[3]",
1777
    /* 6c */ "NROUND[0]", "NROUND[1]", "NROUND[2]", "NROUND[3]",
1778
    /* 70 */ "WCVTF", "INST_71", "INST_72", "DELTAC1",
1779
    /* 74 */ "DELTAC2", "DELTAC3", "SROUND", "S45ROUND",
1780
    /* 78 */ "JROT", "JROF", "ROFF", "INST_7B",
1781
    /* 7c */ "RUTG", "RDTG", "SANGW", "AA",
1782
    /* 80 */ "FLIPPT", "FLIPRGON", "FLIPRGOFF", "INST_83",
1783
    /* 84 */ "INST_84", "SCANCTRL", "INST_86", "INST_87",
1784
    /* 88 */ "GETINFO", "INST_89", "ROLL", "MAX",
1785
    /* 8c */ "MIN", "SCANTYPE", "INSTCTRL", "INST_8F",
1786
    /* 90 */ "INST_90", "INST_91", "INST_92", "INST_93",
1787
    /* 94 */ "INST_94", "INST_95", "INST_96", "INST_97",
1788
    /* 98 */ "INST_98", "INST_99", "INST_9A", "INST_9B",
1789
    /* 9c */ "INST_9C", "INST_9D", "INST_9E", "INST_9F",
1790
    /* a0 */ "INST_A0", "INST_A1", "INST_A2", "INST_A3",
1791
    /* a4 */ "INST_A4", "INST_A5", "INST_A6", "INST_A7",
1792
    /* a8 */ "INST_A8", "INST_A9", "INST_AA", "INST_AB",
1793
    /* ac */ "INST_AC", "INST_AD", "INST_AE", "INST_AF",
1794
    /* b0 */ "PUSHB[0]", "PUSHB[1]", "PUSHB[2]", "PUSHB[3]",
1795
    /* b4 */ "PUSHB[4]", "PUSHB[5]", "PUSHB[6]", "PUSHB[7]",
1796
    /* b8 */ "PUSHW[0]", "PUSHW[1]", "PUSHW[2]", "PUSHW[3]",
1797
    /* bc */ "PUSHW[4]", "PUSHW[5]", "PUSHW[6]", "PUSHW[7]",
1798
    /* c0 */ "INST_C0", "INST_C1", "INST_C2", "INST_C3",
1799
    /* c4 */ "INST_C4", "INST_C5", "INST_C6", "INST_C7",
1800
    /* c8 */ "INST_C8", "INST_C9", "INST_CA", "INST_CB",
1801
    /* cc */ "INST_CC", "INST_CD", "INST_CE", "INST_CF",
1802
    /* d0 */ "INST_D0", "INST_D1", "INST_D2", "INST_D3",
1803
    /* d4 */ "INST_D4", "INST_D5", "INST_D6", "INST_D7",
1804
    /* d8 */ "INST_D8", "INST_D9", "INST_DA", "INST_DB",
1805
    /* dc */ "INST_DC", "INST_DD", "INST_DE", "INST_DF",
1806
    /* e0 */ "MIRP00000", "MIRP00001", "MIRP00010", "MIRP00011",
1807
    /* e4 */ "MIRP00100", "MIRP00101", "MIRP00110", "MIRP00111",
1808
    /* e8 */ "MIRP01000", "MIRP01001", "MIRP01010", "MIRP01011",
1809
    /* ec */ "MIRP01100", "MIRP01101", "MIRP01110", "MIRP01111",
1810
    /* f0 */ "MIRP10000", "MIRP10001", "MIRP10010", "MIRP10011",
1811
    /* f4 */ "MIRP10100", "MIRP10101", "MIRP10110", "MIRP10111",
1812
    /* f8 */ "MIRP11000", "MIRP11001", "MIRP11010", "MIRP11011",
1813
    /* fc */ "MIRP11100", "MIRP11101", "MIRP11110", "MIRP11111"
1814
  };
1815
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.