apwfreetypelib

Check-in [4b013f08ed]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:fixes and made Set of enums for Curve flags and Load flags.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:4b013f08edf7159af7208d68f784579050b27a55
User & Date: arnulf 2015-02-01 19:57:36
Context
2015-02-06
21:18
make glyph flags/tags a Set. fixes. check-in: ef8376af8c user: arnulf tags: trunk
2015-02-01
19:57
fixes and made Set of enums for Curve flags and Load flags. check-in: 4b013f08ed user: arnulf tags: trunk
12:45
fixes, code moving and changes. check-in: 1c81d958fa user: arnulf tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to aftbase/FTGlyphLoaderRec.java.

16
17
18
19
20
21
22


23
24
25
26
27
28
29
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
import android.util.Log;

import org.apwtcl.apwfreetypelib.afttruetype.TTFaceRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTLoaderRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTSizeRec;
import org.apwtcl.apwfreetypelib.aftttinterpreter.TTOpCode;
import org.apwtcl.apwfreetypelib.aftutil.*;



  /* ===================================================================== */
  /*    FTGlyphLoaderRec                                                   */
  /*                                                                       */
  /* ===================================================================== */

public class FTGlyphLoaderRec extends FTDebug {
................................................................................
        if (new_max > Flags.Outline.POINTS_MAX.getVal()) {
          return FTError.ErrorTag.GLYPH_ARRAY_TOO_LARGE;
        }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "FT_RENEW_ARRAY: base.outline.points: "+base.getPoints()+"!");
        base.setPoints((FTVectorRec[]) FTUtil.FT_RENEW_ARRAY(base.getPoints(), FTUtilFlags.ArrayType.FT_VECTOR, old_max, new_max));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "after FT_RENEW_ARRAY: base.outline.points: "+base.getPoints()+"!");
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "FT_RENEW_ARRAY: base.outline.tags: "+base.getTags());
        base.setTags((Flags.Curve[])FTUtil.FT_RENEW_ARRAY(base.getTags(), FTUtilFlags.ArrayType.CURVE, old_max, new_max));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "after FT_RENEW_ARRAY: base.outline.tags: "+base.getTags());
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "FT_RENEW_ARRAY base.extra_points: "+base.getExtra_points()+"!use_extra: "+use_extra+"!");
        if (use_extra) {
          base.setExtra_points((FTVectorRec[])FTUtil.FT_RENEW_ARRAY(base.getExtra_points(), FTUtilFlags.ArrayType.FT_VECTOR, old_max * 2, new_max * 2));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "after FT_RENEW_ARRAY base.extra_points: "+base.getExtra_points()+"!use_extra: "+use_extra+"!");
          for (k = 0; k < old_max; k++) {
            base.getExtra_points()[new_max + k].setX(base.getExtra_points()[old_max + k].getX());







>
>







 







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
import android.util.Log;

import org.apwtcl.apwfreetypelib.afttruetype.TTFaceRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTLoaderRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTSizeRec;
import org.apwtcl.apwfreetypelib.aftttinterpreter.TTOpCode;
import org.apwtcl.apwfreetypelib.aftutil.*;

import java.util.Set;

  /* ===================================================================== */
  /*    FTGlyphLoaderRec                                                   */
  /*                                                                       */
  /* ===================================================================== */

public class FTGlyphLoaderRec extends FTDebug {
................................................................................
        if (new_max > Flags.Outline.POINTS_MAX.getVal()) {
          return FTError.ErrorTag.GLYPH_ARRAY_TOO_LARGE;
        }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "FT_RENEW_ARRAY: base.outline.points: "+base.getPoints()+"!");
        base.setPoints((FTVectorRec[]) FTUtil.FT_RENEW_ARRAY(base.getPoints(), FTUtilFlags.ArrayType.FT_VECTOR, old_max, new_max));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "after FT_RENEW_ARRAY: base.outline.points: "+base.getPoints()+"!");
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "FT_RENEW_ARRAY: base.outline.tags: "+base.getTags());
        base.setTags((Set<Flags.Curve>[])FTUtil.FT_RENEW_ARRAY(base.getTags(), FTUtilFlags.ArrayType.CURVE, old_max, new_max));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "after FT_RENEW_ARRAY: base.outline.tags: "+base.getTags());
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "FT_RENEW_ARRAY base.extra_points: "+base.getExtra_points()+"!use_extra: "+use_extra+"!");
        if (use_extra) {
          base.setExtra_points((FTVectorRec[])FTUtil.FT_RENEW_ARRAY(base.getExtra_points(), FTUtilFlags.ArrayType.FT_VECTOR, old_max * 2, new_max * 2));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "after FT_RENEW_ARRAY base.extra_points: "+base.getExtra_points()+"!use_extra: "+use_extra+"!");
          for (k = 0; k < old_max; k++) {
            base.getExtra_points()[new_max + k].setX(base.getExtra_points()[old_max + k].getX());

Changes to aftbase/FTOutlineRec.java.

60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
...
616
617
618
619
620
621
622
623
624
625
626
627
628






629
630
631










632
633
634
635
636
637
638
639
640
641
642
643
644
645
  /*    The B/W rasterizer only checks bit~2 in the `tags' array for the   */
  /*    first point of each contour.  The drop-out mode as given with      */
  /*    @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and       */
  /*    @FT_OUTLINE_INCLUDE_STUBS in `flags' is then overridden.           */
  /*                                                                       */
  /* ===================================================================== */


import android.util.SparseArray;

import org.apwtcl.apwfreetypelib.aftutil.FTCalc;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTMatrixRec;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;



public class FTOutlineRec extends FTDebug {
  private static int oid = 0;

  private int id;
  private static String TAG = "FTOutlineRec";

  protected int n_contours = 0;          /* number of contours in glyph    */
  protected int n_points = 0;            /* number of points in the glyph  */
  protected FTVectorRec[] points = null; /* the outline's points           */
  protected int points_idx = 0;
  protected Flags.Curve[] tags = null;   /* the points flags               */
  protected int tags_idx = 0;
  protected int[] contours = null;       /* the contour end points         */
  protected int contours_idx = 0;
  protected int flags = 0;               /* outline masks                  */

  /* ==================== FTOutlineRec ================================== */
  public FTOutlineRec() {
................................................................................
    FTVectorRec v_control = new FTVectorRec();
    FTVectorRec v_start;
    int pointIdx;
    int limit;
    int tagsIdx;
    int n;        /* index of contour in outline     */
    int first = 0; /* index of first point in contour */
    Flags.Curve tag;       /* current point's state           */
    int shift;
    int delta;
    boolean doConic = true;
    boolean doContinue = false;
    boolean isClosed = false;

Debug(0, DebugTag.DBG_RENDER, TAG, "ftoutline FTOutlineDecompose");
................................................................................
      v_last.setX(((v_last.getX()) << shift) - delta);
      v_last.setY(((v_last.getY()) << shift) - delta);
      v_control.setX(v_start.getX());
      v_control.setY(v_start.getY());
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("v_start: %d %d v_last: %d %d", v_start.getX(), v_start.getY(), v_last.getX(), v_last.getY()));
      pointIdx = first;
      tagsIdx = first;
      tag = Flags.Curve.getTableTag(tags[tagsIdx].getVal() & 3);
      /* A contour cannot start with a cubic control point! */
      if (tag == Flags.Curve.CUBIC) {
        return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
      }
      /* check first point to determine origin */
      if (tag == Flags.Curve.CONIC) {
        /* first point is conic control.  Yes, this happens. */
        if ((tags[last].getVal() & 3) == Flags.Curve.ON.getVal()) {
          /* start at last point if it is on the curve */
          v_start.setX(v_last.getX());
          v_start.setY(v_last.getY());
          limit--;
        } else {
          /* if both first and last points are conic,         */
          /* start at their middle and record its position    */
................................................................................
        return error;
      }
      while (pointIdx < limit) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("decompose1: pointIdx: %d, limit: %d, n: %d, outline.n_contours: %d", pointIdx, limit, n, n_contours));
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==2 v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
        pointIdx++;
        tagsIdx++;
        tag = Flags.Curve.getTableTag(tags[tagsIdx].getVal() & 3);
        switch (tag)
        {
        case ON:  /* emit a single line_to */
          {
            FTVectorRec vec = new FTVectorRec();

Debug(0, DebugTag.DBG_RENDER, TAG, "FT_CURVE_TAG_ON");
            vec.setX((((points[pointIdx].getX())) << shift) - delta);
            vec.setY(((points[pointIdx].getY()) << shift) - delta);
            FTTrace.Trace(7, TAG, String.format("  line to (%.2f, %.2f)\n",
                        vec.getX() / 64.0, vec.getY() / 64.0));
            error = func_interface.lineTo(vec, user);
            if (error != FTError.ErrorTag.ERR_OK) {
              FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
              return error;
            }
            continue;
          }
        case CONIC:  /* consume conic arcs */
Debug(0, DebugTag.DBG_RENDER, TAG, "FT_CURVE_TAG_CONIC");
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==3a v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
          v_control.setX(((points[pointIdx].getX()) << shift) - delta);
          v_control.setY(((points[pointIdx].getY()) << shift) - delta);
          doConic = true;
          while (doConic) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("decompose doConic: pointIdx: %d,  limit: %d", pointIdx, limit));
            doConic = false;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==3b v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
            doContinue = false;
            if (pointIdx < limit) {
              FTVectorRec vec = new FTVectorRec();
              FTVectorRec v_middle = new FTVectorRec();

              pointIdx++;
              tagsIdx++;
              tag = Flags.Curve.getTableTag(tags[tagsIdx].getVal() & 3);
              vec.setX(((points[pointIdx].getX()) << shift) - delta);
              vec.setY(((points[pointIdx].getY()) << shift) - delta);
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("tag: %d, tagIdx: %d, pointIdx: %d, limit: %d, vec.x: %d, vec.y: %d", tag, tagsIdx, pointIdx, limit, vec.getX(), vec.getY()));
              if (tag == Flags.Curve.ON) {
                FTTrace.Trace(0, TAG, String.format("  1 conic to (%.2f, %.2f)"+
                          " with control (%.2f, %.2f)",
                          vec.getX() / 64.0, vec.getY() / 64.0,
                          v_control.getX() / 64.0, v_control.getY() / 64.0));
                error = func_interface.conicTo(v_control, vec, user);
Debug(0, DebugTag.DBG_RENDER, TAG, "Decompose2: after call conic_to");
                if (error != FTError.ErrorTag.ERR_OK) {
                  FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
                  return error;
                }
                doContinue = true;
                break;
              }
              if (tag != Flags.Curve.CONIC) {
                return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
              }
              v_middle.setX((v_control.getX() + vec.getX()) / 2);
              v_middle.setY((v_control.getY() + vec.getY()) / 2);
              FTTrace.Trace(7, TAG, String.format("  2 conic to (%.2f, %.2f)"+
                        " with control (%.2f, %.2f)",
                        v_middle.getX() / 64.0, v_middle.getY() / 64.0,
                        v_control.getX() / 64.0, v_control.getY() / 64.0));
              error = func_interface.conicTo(v_control, v_middle, user);
 Debug(0, DebugTag.DBG_RENDER, TAG, "Decompose3: after call conic_to");
              if (error != FTError.ErrorTag.ERR_OK) {
                FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
                return error;
              }
              v_control.setX(vec.getX());
              v_control.setY(vec.getY());
              doConic = true;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==4a v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
            }
          }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==4b v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
          if (doContinue) {
            continue;
          }
          FTTrace.Trace(8, TAG, String.format(" 3 conic to (%.2f, %.2f)"+
                      " with control (%.2f, %.2f)",
                      v_start.getX() / 64.0, v_start.getY() / 64.0,
                      v_control.getX() / 64.0, v_control.getY() / 64.0));
          error = func_interface.conicTo(v_control, v_start, user);
          if (error != FTError.ErrorTag.ERR_OK) {
            FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
            return error;
          }
          isClosed = true;
          break;
        default:  /* FT_CURVE_TAG_CUBIC */
          {
            FTVectorRec vec1 = new FTVectorRec();
            FTVectorRec vec2 = new FTVectorRec();

Debug(0, DebugTag.DBG_RENDER, TAG, "FT_CURVE_TAG_CUBIC");
            if (pointIdx + 1 > limit ||
                 (tags[tagsIdx + 1].getVal() & 3) != Flags.Curve.CUBIC.getVal()) {
              return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
            }
            pointIdx += 2;
            tagsIdx += 2;
            vec1.setX((((points[pointIdx - 2].getX()) << shift) - delta));
            vec1.setY((((points[pointIdx - 2].getY()) << shift) - delta));
            vec2.setX((((points[pointIdx - 1].getX()) << shift) - delta));
................................................................................

  /* ==================== setPoints ================================== */
  public void setPoints(FTVectorRec[] points) {
    this.points = points;
  }

  /* ==================== getTag ================================== */
  public Flags.Curve getTag(int idx) {
    return tags[tags_idx+idx];
  }

  /* ==================== setTag ================================== */
  public void setTag(int idx, Flags.Curve tag) {






    tags[tags_idx+idx] = tag;
  }











  /* ==================== getTags ================================== */
  public Flags.Curve[] getTags() {
    return tags;
  }

  /* ==================== setTags ================================== */
  public void setTags(Flags.Curve[] tags) {
    this.tags = tags;
  }

  /* ==================== getContour ================================== */
  public int getContour(int idx) {
    return contours[contours_idx+idx];
  }







>









>
>











|







 







|







 







|

|



|

|







 







|
|
<
|
<
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|




|

|







|


|
|
|
|
|
|

|







|




|
|
|
|

|







|


|



|
|
|
|






|
|






|







 







|





>
>
>
>
>
>



>
>
>
>
>
>
>
>
>
>

|




|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
...
402
403
404
405
406
407
408
409
410

411

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
...
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  /*    The B/W rasterizer only checks bit~2 in the `tags' array for the   */
  /*    first point of each contour.  The drop-out mode as given with      */
  /*    @FT_OUTLINE_IGNORE_DROPOUTS, @FT_OUTLINE_SMART_DROPOUTS, and       */
  /*    @FT_OUTLINE_INCLUDE_STUBS in `flags' is then overridden.           */
  /*                                                                       */
  /* ===================================================================== */

import android.support.annotation.NonNull;
import android.util.SparseArray;

import org.apwtcl.apwfreetypelib.aftutil.FTCalc;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTMatrixRec;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

import java.util.Set;

public class FTOutlineRec extends FTDebug {
  private static int oid = 0;

  private int id;
  private static String TAG = "FTOutlineRec";

  protected int n_contours = 0;          /* number of contours in glyph    */
  protected int n_points = 0;            /* number of points in the glyph  */
  protected FTVectorRec[] points = null; /* the outline's points           */
  protected int points_idx = 0;
  protected Set<Flags.Curve>[] tags = null;   /* the points flags               */
  protected int tags_idx = 0;
  protected int[] contours = null;       /* the contour end points         */
  protected int contours_idx = 0;
  protected int flags = 0;               /* outline masks                  */

  /* ==================== FTOutlineRec ================================== */
  public FTOutlineRec() {
................................................................................
    FTVectorRec v_control = new FTVectorRec();
    FTVectorRec v_start;
    int pointIdx;
    int limit;
    int tagsIdx;
    int n;        /* index of contour in outline     */
    int first = 0; /* index of first point in contour */
    Set<Flags.Curve> tag;       /* current point's state           */
    int shift;
    int delta;
    boolean doConic = true;
    boolean doContinue = false;
    boolean isClosed = false;

Debug(0, DebugTag.DBG_RENDER, TAG, "ftoutline FTOutlineDecompose");
................................................................................
      v_last.setX(((v_last.getX()) << shift) - delta);
      v_last.setY(((v_last.getY()) << shift) - delta);
      v_control.setX(v_start.getX());
      v_control.setY(v_start.getY());
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("v_start: %d %d v_last: %d %d", v_start.getX(), v_start.getY(), v_last.getX(), v_last.getY()));
      pointIdx = first;
      tagsIdx = first;
      tag = tags[tagsIdx];
      /* A contour cannot start with a cubic control point! */
      if (tag.contains(Flags.Curve.CUBIC)) {
        return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
      }
      /* check first point to determine origin */
      if (tag.contains(Flags.Curve.CONIC)) {
        /* first point is conic control.  Yes, this happens. */
        if (tags[last].contains(Flags.Curve.ON)) {
          /* start at last point if it is on the curve */
          v_start.setX(v_last.getX());
          v_start.setY(v_last.getY());
          limit--;
        } else {
          /* if both first and last points are conic,         */
          /* start at their middle and record its position    */
................................................................................
        return error;
      }
      while (pointIdx < limit) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("decompose1: pointIdx: %d, limit: %d, n: %d, outline.n_contours: %d", pointIdx, limit, n, n_contours));
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==2 v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
        pointIdx++;
        tagsIdx++;
        tag = tags[tagsIdx];
        if (tag.contains(Flags.Curve.ON)) {

          /* emit a single line_to */

          FTVectorRec vec = new FTVectorRec();

Debug(0, DebugTag.DBG_RENDER, TAG, "FT_CURVE_TAG_ON");
          vec.setX((((points[pointIdx].getX())) << shift) - delta);
          vec.setY(((points[pointIdx].getY()) << shift) - delta);
          FTTrace.Trace(7, TAG, String.format("  line to (%.2f, %.2f)\n",
                vec.getX() / 64.0, vec.getY() / 64.0));
          error = func_interface.lineTo(vec, user);
          if (error != FTError.ErrorTag.ERR_OK) {
            FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
            return error;
          }
          continue;
        }
        if (tag.contains(Flags.Curve.CONIC)) {  /* consume conic arcs */
          Debug(0, DebugTag.DBG_RENDER, TAG, "FT_CURVE_TAG_CONIC");
          Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==3a v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
          v_control.setX(((points[pointIdx].getX()) << shift) - delta);
          v_control.setY(((points[pointIdx].getY()) << shift) - delta);
          doConic = true;
          while (doConic) {
            Debug(0, DebugTag.DBG_RENDER, TAG, String.format("decompose doConic: pointIdx: %d,  limit: %d", pointIdx, limit));
            doConic = false;
            Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==3b v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
            doContinue = false;
            if (pointIdx < limit) {
              FTVectorRec vec = new FTVectorRec();
              FTVectorRec v_middle = new FTVectorRec();

              pointIdx++;
              tagsIdx++;
              tag = tags[tagsIdx];
              vec.setX(((points[pointIdx].getX()) << shift) - delta);
              vec.setY(((points[pointIdx].getY()) << shift) - delta);
              Debug(0, DebugTag.DBG_RENDER, TAG, String.format("tag: %d, tagIdx: %d, pointIdx: %d, limit: %d, vec.x: %d, vec.y: %d", tag, tagsIdx, pointIdx, limit, vec.getX(), vec.getY()));
              if (tag.contains(Flags.Curve.ON)) {
                FTTrace.Trace(0, TAG, String.format("  1 conic to (%.2f, %.2f)" +
                        " with control (%.2f, %.2f)",
                    vec.getX() / 64.0, vec.getY() / 64.0,
                    v_control.getX() / 64.0, v_control.getY() / 64.0));
                error = func_interface.conicTo(v_control, vec, user);
                Debug(0, DebugTag.DBG_RENDER, TAG, "Decompose2: after call conic_to");
                if (error != FTError.ErrorTag.ERR_OK) {
                  FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
                  return error;
                }
                doContinue = true;
                break;
              }
              if (!tag.contains(Flags.Curve.CONIC)) {
                return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
              }
              v_middle.setX((v_control.getX() + vec.getX()) / 2);
              v_middle.setY((v_control.getY() + vec.getY()) / 2);
              FTTrace.Trace(7, TAG, String.format("  2 conic to (%.2f, %.2f)" +
                      " with control (%.2f, %.2f)",
                  v_middle.getX() / 64.0, v_middle.getY() / 64.0,
                  v_control.getX() / 64.0, v_control.getY() / 64.0));
              error = func_interface.conicTo(v_control, v_middle, user);
              Debug(0, DebugTag.DBG_RENDER, TAG, "Decompose3: after call conic_to");
              if (error != FTError.ErrorTag.ERR_OK) {
                FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
                return error;
              }
              v_control.setX(vec.getX());
              v_control.setY(vec.getY());
              doConic = true;
              Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==4a v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
            }
          }
          Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==4b v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
          if (doContinue) {
            continue;
          }
          FTTrace.Trace(8, TAG, String.format(" 3 conic to (%.2f, %.2f)" +
                  " with control (%.2f, %.2f)",
              v_start.getX() / 64.0, v_start.getY() / 64.0,
              v_control.getX() / 64.0, v_control.getY() / 64.0));
          error = func_interface.conicTo(v_control, v_start, user);
          if (error != FTError.ErrorTag.ERR_OK) {
            FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
            return error;
          }
          isClosed = true;
        } else {
          /* FT_CURVE_TAG_CUBIC */
          {
            FTVectorRec vec1 = new FTVectorRec();
            FTVectorRec vec2 = new FTVectorRec();

Debug(0, DebugTag.DBG_RENDER, TAG, "FT_CURVE_TAG_CUBIC");
            if (pointIdx + 1 > limit ||
                 (!tags[tagsIdx + 1].contains(Flags.Curve.CUBIC))) {
              return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
            }
            pointIdx += 2;
            tagsIdx += 2;
            vec1.setX((((points[pointIdx - 2].getX()) << shift) - delta));
            vec1.setY((((points[pointIdx - 2].getY()) << shift) - delta));
            vec2.setX((((points[pointIdx - 1].getX()) << shift) - delta));
................................................................................

  /* ==================== setPoints ================================== */
  public void setPoints(FTVectorRec[] points) {
    this.points = points;
  }

  /* ==================== getTag ================================== */
  public Set<Flags.Curve> getTag(int idx) {
    return tags[tags_idx+idx];
  }

  /* ==================== setTag ================================== */
  public void setTag(int idx, Flags.Curve tag) {
    tags[tags_idx+idx].clear();
    tags[tags_idx+idx].add(tag);
  }

  /* ==================== setTag ================================== */
  public void setTag(int idx, Set<Flags.Curve> tag) {
    tags[tags_idx+idx] = tag;
  }

  /* ==================== addTag ================================== */
  public void addTag(int idx, Flags.Curve tag) {
    tags[tags_idx+idx].add(tag);
  }

  /* ==================== removeTag ================================== */
  public void removeTag(int idx, Flags.Curve tag) {
    tags[tags_idx+idx].remove(tag);
  }

  /* ==================== getTags ================================== */
  public Set<Flags.Curve>[] getTags() {
    return tags;
  }

  /* ==================== setTags ================================== */
  public void setTags(Set<Flags.Curve>[] tags) {
    this.tags = tags;
  }

  /* ==================== getContour ================================== */
  public int getContour(int idx) {
    return contours[contours_idx+idx];
  }

Changes to aftbase/Flags.java.

11
12
13
14
15
16
17



18
19
20
21
22
23
24
...
373
374
375
376
377
378
379



























380
381
382
383
384
385
386
...
536
537
538
539
540
541
542

543
544
545
546
547









548
549
550
551
552
553
554
555
556
557


















558
559
560
561
562
563
564
 *  See the file "license.terms" for information on usage and
 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * =====================================================================
 */

import android.util.SparseArray;




public class Flags {

  public enum Module {
    FONT_DRIVER(1, "this module is a font driver"),
    RENDERER(2, "this module is a renderer"),
    HINTER(4, "this module is a glyph hinter"),
    DRIVER_STYLER(8, "this module is a styler"),
................................................................................
      for (Load t : values()) {
        tagToLoadMapping.put(t.val, t);
      }
    }
    private Load(int val, String str) {
      this.val = val;
      this.str = str;



























    }
    public int getVal() {
      return val;
    }
  }

  public enum LoadType {
................................................................................
    HAS_SCANMODE(4, "FT_CURVE_TAG_HAS_SCANMODE"),
    TOUCH_X(8, "FT_CURVE_TAG_TOUCH_X"), /* reserved for the TrueType hinter */
    TOUCH_Y(16, "FT_CURVE_TAG_TOUCH_Y"), /* reserved for the TrueType hinter */
    TOUCH_BOTH((Curve.TOUCH_X.getVal() | Curve.TOUCH_Y.getVal()), "FT_CURVE_TAG_TOUCH_BOTH");
    private int val;
    private String str;
    private static SparseArray<Curve> tagToCurveMapping;

    public static Curve getTableTag(int i) {
      if (tagToCurveMapping == null) {
        initMapping();
      }
      return tagToCurveMapping.get(i);









    }
    private static void initMapping() {
      tagToCurveMapping = new SparseArray<Curve>();
      for (Curve t : values()) {
        tagToCurveMapping.put(t.val, t);
      }
    }
    private Curve(int val, String str) {
      this.val = val;
      this.str = str;


















    }
    public int getVal() {
      return val;
    }
  }

  public enum SubGlyph {







>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>





>
>
>
>
>
>
>
>
>










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
 *  See the file "license.terms" for information on usage and
 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * =====================================================================
 */

import android.util.SparseArray;

import java.util.HashSet;
import java.util.Set;

public class Flags {

  public enum Module {
    FONT_DRIVER(1, "this module is a font driver"),
    RENDERER(2, "this module is a renderer"),
    HINTER(4, "this module is a glyph hinter"),
    DRIVER_STYLER(8, "this module is a styler"),
................................................................................
      for (Load t : values()) {
        tagToLoadMapping.put(t.val, t);
      }
    }
    private Load(int val, String str) {
      this.val = val;
      this.str = str;
    }
    public static Set<Load> makeTableTagSet(int value) {
      Set<Load> flags = new HashSet<>();
      for (Load t : values()) {
        if ((value & t.getVal()) != 0) {
          flags.add(t);
        }
      }
      return flags;
    }
    public static String CurveSetToString(Set<Curve> flags) {
      StringBuffer str = new StringBuffer();
      for (Load t : values()) {
        if (flags.contains(t)) {
          str.append(" "+t.toString());
        }
      }
      return str.toString();
    }
    public static int CurveSetToInt(Set<Curve> flags) {
      int val = 0;
      for (Load t : values()) {
        if (flags.contains(t)) {
          val += t.getVal();
        }
      }
      return val;
    }
    public int getVal() {
      return val;
    }
  }

  public enum LoadType {
................................................................................
    HAS_SCANMODE(4, "FT_CURVE_TAG_HAS_SCANMODE"),
    TOUCH_X(8, "FT_CURVE_TAG_TOUCH_X"), /* reserved for the TrueType hinter */
    TOUCH_Y(16, "FT_CURVE_TAG_TOUCH_Y"), /* reserved for the TrueType hinter */
    TOUCH_BOTH((Curve.TOUCH_X.getVal() | Curve.TOUCH_Y.getVal()), "FT_CURVE_TAG_TOUCH_BOTH");
    private int val;
    private String str;
    private static SparseArray<Curve> tagToCurveMapping;

    public static Curve getTableTag(int i) {
      if (tagToCurveMapping == null) {
        initMapping();
      }
      return tagToCurveMapping.get(i);
    }
    public static Set<Curve> makeTableTagSet(int value) {
      Set<Curve> flags = new HashSet<>();
      for (Curve t : values()) {
        if ((value & t.getVal()) != 0) {
          flags.add(t);
        }
      }
      return flags;
    }
    private static void initMapping() {
      tagToCurveMapping = new SparseArray<Curve>();
      for (Curve t : values()) {
        tagToCurveMapping.put(t.val, t);
      }
    }
    private Curve(int val, String str) {
      this.val = val;
      this.str = str;
    }
    public static String CurveSetToString(Set<Curve> flags) {
      StringBuffer str = new StringBuffer();
      for (Curve t : values()) {
        if (flags.contains(t)) {
          str.append(" "+t.toString());
        }
      }
      return str.toString();
    }
    public static int CurveSetToInt(Set<Curve> flags) {
      int val = 0;
      for (Curve t : values()) {
        if (flags.contains(t)) {
          val += t.getVal();
        }
      }
      return val;
    }
    public int getVal() {
      return val;
    }
  }

  public enum SubGlyph {

Changes to afttruetype/TTGlyphLoaderRec.java.

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

  /* =====================================================================
   * tt_load_simple_glyph
   * =====================================================================
   */
  public FTError.ErrorTag tt_load_simple_glyph(TTLoaderRec loader) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_load_simple_glyph");
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    int n_contours = loader.getN_contours();
    TTFaceRec ttface = (TTFaceRec)loader.getFace();
    TTGlyphSimpleRec ttglyph;
    int contour_idx;
    int contour_limit;
    int n_ins;
    int n_points;
................................................................................
    n_ins = ttglyph.getInstructions_length();
    FTTrace.Trace(7, TAG, String.format("  Instructions size: %d", n_ins));
    if (n_ins > ttface.getMax_profile().getMaxSizeOfInstructions()) {
      FTTrace.Trace(7, TAG, String.format("tt_load_simple_glyph: too many instructions (%d)", n_ins));
      error = FTError.ErrorTag.GLYPH_TOO_MANY_HINTS;
      return error;
    }
    if ((loader.getLoad_flags().getVal() & Flags.Load.NO_AUTOHINT.getVal()) == 0) {
      int i;

      loader.getGlyph().setControl_len(n_ins);
      loader.getGlyph().setControl_data(loader.getExec().glyphIns);
      for (i = 0; i < n_ins; i++) {
        loader.getExec().glyphIns[i] = TTOpCode.OpCode.getTableTag(ttglyph.getInstructions()[i] & 0xFF);
        if (loader.getExec().glyphIns[i] == null) {
................................................................................
//        FT_MEM_COPY( loader.exec.glyphIns, p, (FT_Long)n_ins );
    }

      /* loading the point tags */
    flag_idx = 0;
    flag_limit = n_points;
    while (flag_idx < flag_limit) {
      current.getTags()[flag_idx++] = Flags.Curve.getTableTag(ttglyph.getTags()[flag_idx]);
      flag_idx++;
    }
for(int t = 0; t < flag_idx; t++) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("Tag: t: %d: 0x%02x: ", t, current.getTags()[t].getVal())+current.getTags()[t]);
}

      /* loading the X and y coordinates */
    vec_limit = n_points;
    for (vec_idx = 0; vec_idx < vec_limit; vec_idx++) {
      current.getPoints()[vec_idx] = ttglyph.getPoints()[vec_idx];
    }







|







 







|







 







|



|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

  /* =====================================================================
   * tt_load_simple_glyph
   * =====================================================================
   */
  public FTError.ErrorTag tt_load_simple_glyph(TTLoaderRec loader) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_load_simple_glyph");
    FTError.ErrorTag error;
    int n_contours = loader.getN_contours();
    TTFaceRec ttface = (TTFaceRec)loader.getFace();
    TTGlyphSimpleRec ttglyph;
    int contour_idx;
    int contour_limit;
    int n_ins;
    int n_points;
................................................................................
    n_ins = ttglyph.getInstructions_length();
    FTTrace.Trace(7, TAG, String.format("  Instructions size: %d", n_ins));
    if (n_ins > ttface.getMax_profile().getMaxSizeOfInstructions()) {
      FTTrace.Trace(7, TAG, String.format("tt_load_simple_glyph: too many instructions (%d)", n_ins));
      error = FTError.ErrorTag.GLYPH_TOO_MANY_HINTS;
      return error;
    }
    if (!loader.getLoad_flags().contains(Flags.Load.NO_AUTOHINT)) {
      int i;

      loader.getGlyph().setControl_len(n_ins);
      loader.getGlyph().setControl_data(loader.getExec().glyphIns);
      for (i = 0; i < n_ins; i++) {
        loader.getExec().glyphIns[i] = TTOpCode.OpCode.getTableTag(ttglyph.getInstructions()[i] & 0xFF);
        if (loader.getExec().glyphIns[i] == null) {
................................................................................
//        FT_MEM_COPY( loader.exec.glyphIns, p, (FT_Long)n_ins );
    }

      /* loading the point tags */
    flag_idx = 0;
    flag_limit = n_points;
    while (flag_idx < flag_limit) {
      current.setTag(flag_idx, Flags.Curve.makeTableTagSet(ttglyph.getTag(flag_idx)));
      flag_idx++;
    }
for(int t = 0; t < flag_idx; t++) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("Tag: t: %d: 0x%02x", t, Flags.Curve.CurveSetToInt(current.getTag(t)))+Flags.Curve.CurveSetToString(current.getTag(t)));
}

      /* loading the X and y coordinates */
    vec_limit = n_points;
    for (vec_idx = 0; vec_idx < vec_limit; vec_idx++) {
      current.getPoints()[vec_idx] = ttglyph.getPoints()[vec_idx];
    }

Changes to afttruetype/TTGlyphSimpleRec.java.

325
326
327
328
329
330
331





332
333
334
335
336
337
338
    this.y_coordinates = y_coordinates;
  }

  /* ==================== getTags ================================== */
  public byte[] getTags() {
    return tags;
  }






  /* ==================== setTags ================================== */
  public void setTags(byte[] tags) {
    this.tags = tags;
  }

  /* ==================== getPoints ================================== */







>
>
>
>
>







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
    this.y_coordinates = y_coordinates;
  }

  /* ==================== getTags ================================== */
  public byte[] getTags() {
    return tags;
  }

  /* ==================== getTags ================================== */
  public byte getTag(int tag_idx) {
    return tags[tag_idx];
  }

  /* ==================== setTags ================================== */
  public void setTags(byte[] tags) {
    this.tags = tags;
  }

  /* ==================== getPoints ================================== */

Changes to afttruetype/TTGlyphSlotRec.java.

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
      return error;
    }
    if ((load_flags & Flags.Load.SBITS_ONLY.getVal()) != 0) {
      error = FTError.ErrorTag.LOAD_INVALID_ARGUMENT;
      return error;
    }
    loader = new TTLoaderRec();
    error = loader.tt_loader_init(ttsize, this, Flags.Load.getTableTag(load_flags), false);
    if (error != FTError.ErrorTag.ERR_OK) {
      return error;
    }
    format = FTTags.GlyphFormat.OUTLINE;
    num_subglyphs = 0;
    outline.setFlags(0);
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "load_truetype_glyph");







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
      return error;
    }
    if ((load_flags & Flags.Load.SBITS_ONLY.getVal()) != 0) {
      error = FTError.ErrorTag.LOAD_INVALID_ARGUMENT;
      return error;
    }
    loader = new TTLoaderRec();
    error = loader.tt_loader_init(ttsize, this, Flags.Load.makeTableTagSet(load_flags), false);
    if (error != FTError.ErrorTag.ERR_OK) {
      return error;
    }
    format = FTTags.GlyphFormat.OUTLINE;
    num_subglyphs = 0;
    outline.setFlags(0);
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "load_truetype_glyph");

Changes to afttruetype/TTGlyphZoneRec.java.

38
39
40
41
42
43
44


45
46
47
48
49
50
51
52



53
54
55
56
57
58
59
..
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
...
297
298
299
300
301
302
303
304



305
306
307
308
309
310
311
...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593











594
595
596
597
598
599
600
  /*                                                                       */
  /*     contours     :: The contours end points.                          */
  /*                                                                       */
  /*     first_point  :: Offset of the current subglyph's first point.     */
  /*                                                                       */
  /* ===================================================================== */




import org.apwtcl.apwfreetypelib.aftbase.FTGlyphLoadRec;
import org.apwtcl.apwfreetypelib.aftbase.Flags;
import org.apwtcl.apwfreetypelib.aftttinterpreter.TTExecContextRec;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;




public class TTGlyphZoneRec extends FTDebug {
  private static int oid = 0;

  private int id;
  private static String TAG = "TTGlyphZoneRec";

................................................................................
  private int n_contours = 0;        /* number of contours          */
  private FTVectorRec[] org = null;  /* original point coordinates  */
  private int org_idx = 0;
  private FTVectorRec[] cur = null;  /* current point coordinates   */
  private int cur_idx = 0;
  private FTVectorRec[] orus = null; /* original (unscaled) point coordinates */
  private int orus_idx = 0;
  private Flags.Curve[] tags = null; /* current touch flags         */
  private int tags_idx = 0;
  private int[] contours = null;     /* contour end points          */
  private int contours_idx = 0;
  private int first_point = 0;       /* offset of first (#0) point  */
  private TTExecContextRec exec = null;

  /* ==================== TTGlyphZoneRec ================================== */
................................................................................
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("org: "+(Object)org+"\n");
    str.append("cur: "+(Object)cur+"\n");
    str.append("orus: "+(Object)orus);
    return str.toString();
  }
 
  /* =====================================================================
   * copy
   * =====================================================================
   */
................................................................................
        orus[i].setY(0);
      }
    }
    orus_idx = 0;

    if (tags != null) {
      for (i = 0; i < tags.length; i++) {
        tags[i] = Flags.Curve.CONIC;
      }
    }
    tags_idx = 0;

    if (contours != null) {
      for (i = 0; i < contours.length; i++) {
        contours[i] = 0;
................................................................................
    for (i = 0; i < maxPoints; i++) {
      zone.cur[i] = new FTVectorRec();
    }
    zone.orus = new FTVectorRec[maxPoints];
    for (i = 0; i < maxPoints; i++) {
      zone.orus[i] = new FTVectorRec();
    }
    zone.tags = new Flags.Curve[maxPoints];



    zone.contours = new int[maxContours];
    zone.max_points = maxPoints;
    zone.max_contours = maxContours;
    zone_ref.Set(zone);
    return error;
  }

................................................................................

  /* ==================== setOrus_idx ================================== */
  public void setOrus_idx(int orus_idx) {
    this.orus_idx = orus_idx;
  }

  /* ==================== getTags ================================== */
  public Flags.Curve[] getTags() {
    return tags;
  }

  /* ==================== getTag ================================== */
  public Flags.Curve getTag(int tag_idx) {
    return tags[tags_idx + tag_idx];
  }

  /* ==================== setTags ================================== */
  public void setTags(Flags.Curve[] tags) {
    this.tags = tags;
  }

  /* ==================== setTags ================================== */
  public void setTag(int tag_idx, Flags.Curve tag) {
    this.tags[tags_idx + tag_idx] = tag;











  }

  /* ==================== getTags_idx ================================== */
  public int getTags_idx() {
    return tags_idx;
  }








>
>








>
>
>







 







|







 







|
|
|







 







|







 







|
>
>
>







 







|




|




|



|

|
>
>
>
>
>
>
>
>
>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
..
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  /*                                                                       */
  /*     contours     :: The contours end points.                          */
  /*                                                                       */
  /*     first_point  :: Offset of the current subglyph's first point.     */
  /*                                                                       */
  /* ===================================================================== */


import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.FTGlyphLoadRec;
import org.apwtcl.apwfreetypelib.aftbase.Flags;
import org.apwtcl.apwfreetypelib.aftttinterpreter.TTExecContextRec;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

import java.util.HashSet;
import java.util.Set;

public class TTGlyphZoneRec extends FTDebug {
  private static int oid = 0;

  private int id;
  private static String TAG = "TTGlyphZoneRec";

................................................................................
  private int n_contours = 0;        /* number of contours          */
  private FTVectorRec[] org = null;  /* original point coordinates  */
  private int org_idx = 0;
  private FTVectorRec[] cur = null;  /* current point coordinates   */
  private int cur_idx = 0;
  private FTVectorRec[] orus = null; /* original (unscaled) point coordinates */
  private int orus_idx = 0;
  private Set<Flags.Curve>[] tags = null; /* current touch flags         */
  private int tags_idx = 0;
  private int[] contours = null;     /* contour end points          */
  private int contours_idx = 0;
  private int first_point = 0;       /* offset of first (#0) point  */
  private TTExecContextRec exec = null;

  /* ==================== TTGlyphZoneRec ================================== */
................................................................................
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("org: "+org+"\n");
    str.append("cur: "+cur+"\n");
    str.append("orus: "+orus);
    return str.toString();
  }
 
  /* =====================================================================
   * copy
   * =====================================================================
   */
................................................................................
        orus[i].setY(0);
      }
    }
    orus_idx = 0;

    if (tags != null) {
      for (i = 0; i < tags.length; i++) {
        tags[i] = new HashSet<>();
      }
    }
    tags_idx = 0;

    if (contours != null) {
      for (i = 0; i < contours.length; i++) {
        contours[i] = 0;
................................................................................
    for (i = 0; i < maxPoints; i++) {
      zone.cur[i] = new FTVectorRec();
    }
    zone.orus = new FTVectorRec[maxPoints];
    for (i = 0; i < maxPoints; i++) {
      zone.orus[i] = new FTVectorRec();
    }
    zone.tags = new Set[maxPoints];
    for (i = 0; i < maxPoints; i++) {
      zone.tags[i] = new HashSet<>();
    }
    zone.contours = new int[maxContours];
    zone.max_points = maxPoints;
    zone.max_contours = maxContours;
    zone_ref.Set(zone);
    return error;
  }

................................................................................

  /* ==================== setOrus_idx ================================== */
  public void setOrus_idx(int orus_idx) {
    this.orus_idx = orus_idx;
  }

  /* ==================== getTags ================================== */
  public Set<Flags.Curve>[] getTags() {
    return tags;
  }

  /* ==================== getTag ================================== */
  public Set<Flags.Curve> getTag(int tag_idx) {
    return tags[tags_idx + tag_idx];
  }

  /* ==================== setTags ================================== */
  public void setTags(Set<Flags.Curve>[] tags) {
    this.tags = tags;
  }

  /* ==================== setTag ================================== */
  public void setTag(int tag_idx, Flags.Curve tag) {
    this.tags[tags_idx + tag_idx].clear();
    this.tags[tags_idx + tag_idx].add(tag);
  }

  /* ==================== addTag ================================== */
  public void addTag(int tag_idx, Flags.Curve tag) {
    this.tags[tags_idx + tag_idx].add(tag);
  }

  /* ==================== addTag ================================== */
  public void removeTag(int tag_idx, Flags.Curve tag) {
    this.tags[tags_idx + tag_idx].remove(tag);
  }

  /* ==================== getTags_idx ================================== */
  public int getTags_idx() {
    return tags_idx;
  }

Changes to afttruetype/TTLoaderRec.java.

33
34
35
36
37
38
39



40
41
42
43
44
45
46
..
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
...
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
...
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
...
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728

729





730
731
732
733
734
735
736
...
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
...
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
...
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
....
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
















1017
1018
1019
1020
1021
1022
1023
1024
1025
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTStreamRec;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;
import org.apwtcl.apwfreetypelib.aftutil.TTUtil;




  /* ===================================================================== */
  /*    TTLoaderRec                                                          */
  /*                                                                       */
  /* ===================================================================== */

public class TTLoaderRec extends FTDebug {
................................................................................
  private int id;
  private static String TAG = "TTLoaderRec";

  private FTFaceRec face = null;
  private FTSizeRec size = null;
  private FTGlyphSlotRec glyph = null;
  private TTGlyphLoaderRec gloader = null;
  private Flags.Load load_flags = Flags.Load.DEFAULT;
  private int glyph_index = 0;
  private FTStreamRec stream = null;
  private int byte_len = 0;
  private int n_contours = 0;
  private FTBBoxRec bbox = null;
  private int left_bearing = 0;
  private int advance = 0;
................................................................................
    return str.toString();
  }

  /* =====================================================================
   * tt_loader_init
   * =====================================================================
   */
  public FTError.ErrorTag tt_loader_init(TTSizeRec size, FTGlyphSlotRec glyph, Flags.Load load_flags, boolean glyf_table_only) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_loader_init");
    TTFaceRec ttface;
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    boolean pedantic = (load_flags.getVal() & Flags.Load.PEDANTIC.getVal()) != 0;

    ttface = (TTFaceRec)glyph.getFace();
    /* load execution context */
    if ((load_flags.getVal() & Flags.Load.NO_HINTING.getVal()) == 0 && !glyf_table_only) {
      TTExecContextRec exec;
      boolean grayscale;
      boolean reexecute = false;

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "fill TTSizeRec\n");
      if (!size.isCvt_ready()) {
        error = size.tt_size_ready_bytecode(pedantic);
................................................................................
      /* query new execution context */

      exec = size.isDebug() ? size.getContext()
                         : ((TTDriverRec)ttface.getDriver()).context;
      if (exec == null) {
        return FTError.ErrorTag.GLYPH_COULD_NOT_FIND_CONTEXT;
      }
      grayscale = (((load_flags.getVal() >> 16) & 15) != FTTags.RenderMode.MONO.getVal());

      exec.TTLoadContext(ttface, size);
      {
        /* a change from mono to grayscale rendering (and vice versa) */
        /* requires a re-execution of the CVT program                 */
        if (grayscale != exec.grayscale) {
          FTTrace.Trace(7, TAG, "tt_loader_init: grayscale change, re-executing `prep' table");
          exec.grayscale = grayscale;
................................................................................
        for (i = 0; i < size.getCvt_size(); i++) {
          size.getCvt()[i] = TTUtil.FTMulFix(ttface.getCvt_table().getCvtValue(i), size.getTtmetrics().getScale());
        }
        size.tt_size_run_prep(pedantic);
      }
      /* see whether the cvt program has disabled hinting */
      if ((exec.graphics_state.getInstruct_control() & 1) != 0) {
        load_flags = Flags.Load.getTableTag(load_flags.getVal() | Flags.Load.NO_HINTING.getVal());
      }
      /* load default graphics state -- if needed */
      if ((exec.graphics_state.getInstruct_control() & 2) != 0) {
        exec.graphics_state = new TTDefaultGraphicsStateClass();
      }
      exec.pedantic_hinting = (load_flags.getVal() & Flags.Load.PEDANTIC.getVal()) != 0;
      this.exec = exec;
      this.base.setExec(exec);
      this.zone.setExec(exec);
      this.instructions = exec.glyphIns;
    }
    /* seek to the beginning of the glyph table -- for Type 42 fonts     */
    /* the table might be accessed from a Postscript stream or something */
................................................................................
      error = FTError.ErrorTag.GLYPH_INVALID_GLYPH_INDEX;
      if (opened_frame) {
        ttface.forgetGlyphFrame(this);
      }
      return error;
    }
    glyph_index = gindex;
    if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
      x_scale = size.getMetrics().getX_scale();
      y_scale = size.getMetrics().getY_scale();
    } else {
      x_scale = 0x10000;
      y_scale = 0x10000;
    }
    tt_get_metrics();
................................................................................
      pp1.setY(0);
      pp2.setX(pp1.getX() + advance);
      pp2.setY(0);
      pp3.setX(0);
      pp3.setY(top_bearing + bbox.getyMax());
      pp4.setX(0);
      pp4.setY(pp3.getY() - vadvance);
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader.pp1.x: %d %d %d %d %d", pp1.getX(), pp2.getX(), pp3.getY(), pp4.getY(), (load_flags.getVal() & Flags.Load.NO_SCALE.getVal())));
      if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
        pp1.setX(TTUtil.FTMulFix(pp1.getX(), x_scale));
        pp2.setX(TTUtil.FTMulFix(pp2.getX(), x_scale));
        pp3.setY(TTUtil.FTMulFix(pp3.getY(), y_scale));
        pp4.setY(TTUtil.FTMulFix(pp4.getY(), y_scale));
      }
      error = FTError.ErrorTag.ERR_OK;
      if (opened_frame) {
................................................................................
        }
        /* store the offset of instructions */
        ins_pos = this.ins_pos;
        /* all data we need are read */
        ttface.forgetGlyphFrame(this);
        opened_frame = false;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp4: loader.pp1.x: %d, loader.pp1.y: %d, loader.pp2.x: %d, loader.pp2.y: %d, loader.pp3.x: %d, loader.pp3.y: %d, loader.pp4.x: %d, loader.pp4.y: %d\n", pp1.getX(), pp1.getY(), pp2.getX(), pp2.getY(), pp3.getX(), pp3.getY(), pp4.getX(), pp4.getY()));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("LOAD_NO_SCALE: %d", (load_flags.getVal() & Flags.Load.NO_SCALE.getVal())));
        if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
          pp1.setX(TTUtil.FTMulFix(pp1.getX(), x_scale));
          pp2.setX(TTUtil.FTMulFix(pp2.getX(), x_scale));
          pp3.setY(TTUtil.FTMulFix(pp3.getY(), y_scale));
          pp4.setY(TTUtil.FTMulFix(pp4.getY(), y_scale));
        }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp5: loader.pp1.x: %d, loader.pp1.y: %d, loader.pp2.x: %d, loader.pp2.y: %d, loader.pp3.x: %d, loader.pp3.y: %d, loader.pp4.x: %d, loader.pp4.y: %d\n", pp1.getX(), pp1.getY(), pp2.getX(), pp2.getY(), pp3.getX(), pp3.getY(), pp4.getX(), pp4.getY()));
        /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
        /* `as is' in the glyph slot (the client application will be     */
        /* responsible for interpreting these data)...                   */
        if ((load_flags.getVal() & Flags.Load.NO_RECURSE.getVal()) != 0) {
          gloader.GlyphLoaderAdd();
          glyph.setFormat(FTTags.GlyphFormat.COMPOSITE);
          if (opened_frame) {
            ttface.forgetGlyphFrame(this);
          }
          return error;
        }
................................................................................
            /* (3): the newly loaded component                              */
            TTProcessCompositeComponent(subglyph, start_point, num_base_points);
          }
          stream = old_stream;
          byte_len = old_byte_len;
          /* process the glyph */
          this.ins_pos = ins_pos;
          if (((load_flags.getVal() & Flags.Load.NO_HINTING.getVal()) != 0) &&
                  ((subglyph.getFlags().getVal() & Flags.LoadType.WE_HAVE_INSTR.getVal()) != 0) && (num_points > start_point)) {
            TTProcessCompositeGlyph(start_point, start_contour);
          } 
        }
      } else {
      /* invalid composite count (negative but not -1) */
      error = FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
................................................................................

    int i;
    for (i = 0; i < gloader.getCurrent().getN_points() + 4; i++) {
//Debug(0, DBG_LOAD_GLYPH, TAG, String.format("PP2: i: %d x: %d y: %d\n", i, loader.gloader.current.outline.points[loader.gloader.current.outline.points_idx + i].x,
//loader.gloader.current.outline.points[loader.gloader.current.outline.points_idx + i].y));
    }
    y_scale = 0x10000;
    if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
      y_scale = ttsize.getMetrics().getY_scale();
    }
    if (glyph.getFormat().getVal() != FTTags.GlyphFormat.COMPOSITE.getVal()) {
      FTReference<FTBBoxRec> bbox_ref = new FTReference<FTBBoxRec>();
      bbox_ref.Set(new FTBBoxRec());
      glyph.getOutline().FTOutlineGetCBox(bbox_ref);
      bbox = bbox_ref.Get();
................................................................................
      /* by the base layer.                                                */
    glyph.setLinearHoriAdvance(linear);
    glyph.getMetrics().setHoriBearingX(bbox.getxMin());
    glyph.getMetrics().setHoriBearingY(bbox.getyMax());
    glyph.getMetrics().setHoriAdvance(pp2.getX() - pp1.getX());
      /* adjust advance width to the value contained in the hdmx table */
    if (ttface.getPostscript().getIsFixedPitch() != 0 &&
        (load_flags.getVal() & Flags.Load.NO_HINTING.getVal()) == 0) {
      int widthpIdx;

      widthpIdx = TTLoad.tt_face_get_device_metrics(ttface, ttsize.getMetrics().getX_ppem(), glyph_index);
      if (widthpIdx != 0) {
        glyph.getMetrics().setHoriAdvance(ttface.getHdmx_table().getRecords()[widthpIdx] << 6);
      }
    }
................................................................................
        } else {
          advance = ttface.getHorizontal().getAscender() - ttface.getHorizontal().getDescender();
        }
        top = (advance - height) / 2;
      }
      glyph.setLinearVertAdvance(advance);
        /* scale the metrics */
      if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
        top = FTCalc.FTMulFix(top, y_scale);
        advance = FTCalc.FTMulFix(advance, y_scale);
      }
        /* XXX: for now, we have no better algorithm for the lsb, but it */
        /*      should work fine.                                        */
        /*                                                               */
      glyph.getMetrics().setVertBearingX(glyph.getMetrics().getHoriBearingX() -
................................................................................

      error = exec.TTSetCodeRange(TTInterpTags.CodeRange.GLYPH, exec.glyphIns, null, n_ins);
      if (error != FTError.ErrorTag.ERR_OK) {
        return error;
      }
      exec.is_composite = is_composite;
      exec.pts.copy(zone);
      debug = ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0 && ((TTSizeRec)size).isDebug());
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "call TTRunContext");
if (gloader.getBase() != null) {
  gloader.getBase().showGloaderGlyph("base before call TTRunContext");
}
if (gloader.getCurrent() != null) {
  gloader.getCurrent().showGloaderGlyph("current before call TTRunContext");
}
zone.showLoaderZone("before call TTRunContext", exec);
      error = exec.TTRunContext(debug);
      if (error != FTError.ErrorTag.ERR_OK && exec.pedantic_hinting) {
        return error;
      }
        /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
      current_outline.getTags()[0] = Flags.Curve.getTableTag(current_outline.getTags()[0].getVal() |

          (exec.graphics_state.getScan_type() << 5) | Flags.Curve.HAS_SCANMODE.getVal());





    }
      /* save glyph phantom points */
    if (!preserve_pps) {
      pp1 = zone.getCurPoint(zone.getN_points() - 4);
      pp2 = zone.getCurPoint(zone.getN_points() - 3);
      pp3 = zone.getCurPoint(zone.getN_points() - 2);
      pp4 = zone.getCurPoint(zone.getN_points() - 1);
................................................................................
    int n_points;

    n_points = gloader.getCurrent().getN_points();
      /* set phantom points */
    gloader.getCurrent().setPoint(n_points, pp1);
    gloader.getCurrent().setPoint(n_points + 1, pp2);
    gloader.getCurrent().setPoint(n_points + 2, pp3);
    gloader.getCurrent().setPoint(n_points + 3, pp4);
    gloader.getCurrent().setTag(n_points, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 1, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 2, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 3, Flags.Curve.CONIC);
    n_points += 4;
    if ((load_flags.getVal() & Flags.Load.NO_HINTING.getVal()) == 0) {
      zone.tt_prepare_zone(gloader.getCurrent(), 0, 0);
      for (int i = 0; i < (zone.getN_points() + 4); i++) {
        zone.setOrusPoint(i, new FTVectorRec());
        zone.setOrusPoint_x(i, zone.getCurPoint_x(i));
        zone.setOrusPoint_y(i, zone.getCurPoint_y(i));
      }
    }
................................................................................
      int vecIdx = 0;
      int limit = n_points;
      int x_scale = 0; /* pacify compiler */
      int y_scale = 0;
      boolean do_scale = false;
      {
          /* scale the glyph */
        if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
          x_scale = size.getMetrics().getX_scale();
          y_scale = size.getMetrics().getY_scale();
          do_scale = true;
        }
      }
      if (do_scale) {
        for (vecIdx = 0; vecIdx < limit; vecIdx++) {
................................................................................
        }
        pp1 = gloader.getCurrent().getPoint(n_points - 4);
        pp2 = gloader.getCurrent().getPoint(n_points - 3);
        pp3 = gloader.getCurrent().getPoint(n_points - 2);
        pp4 = gloader.getCurrent().getPoint(n_points - 1);
      }
    }
    if ((load_flags.getVal() & Flags.Load.NO_HINTING.getVal()) == 0) {
      zone.setN_points(zone.getN_points() + 4);
      error = HintGlyph(false);
    }
    return error;
  }

  /* =====================================================================
................................................................................
          /* This algorithm is a guess and works much better than the above.       */
          /*                                                                       */
        int mac_xscale = FTCalc.FTHypot(subglyph.getTransform().getXx(), subglyph.getTransform().getXy());
        int mac_yscale = FTCalc.FTHypot(subglyph.getTransform().getYy(), subglyph.getTransform().getYx());
        x = TTUtil.FTMulFix(x, mac_xscale);
        y = TTUtil.FTMulFix(y, mac_yscale);
      }
      if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
        int x_scale = size.getMetrics().getX_scale();
        int y_scale = size.getMetrics().getY_scale();
        x = TTUtil.FTMulFix(x, x_scale);
        y = TTUtil.FTMulFix(y, y_scale);
        if ((subglyph.getFlags().getVal() & Flags.LoadType.ROUND_XY_TO_GRID.getVal()) != 0) {
          x = FTCalc.FT_PIX_ROUND(x);
          y = FTCalc.FT_PIX_ROUND(y);
................................................................................
      glyph.setControl_data(exec.glyphIns);
      glyph.setControl_len(n_ins);
    }
    zone.tt_prepare_zone(gloader.getBase(), start_point, start_contour);
      /* Some points are likely touched during execution of  */
      /* instructions on components.  So let's untouch them. */
    for (i = start_point; i < zone.getN_points(); i++) {
      zone.setTag(i, Flags.Curve.getTableTag(zone.getTag(i).getVal() & ~Flags.Curve.TOUCH_BOTH.getVal()));
    }
    zone.setN_points(zone.getN_points() + 4);
    return HintGlyph(true);
  }

  /* ==================== getFace ================================== */
  public FTFaceRec getFace() {
................................................................................

  /* ==================== setGloader ================================== */
  public void setGloader(TTGlyphLoaderRec gloader) {
    this.gloader = gloader;
  }

  /* ==================== getLoad_flags ================================== */
  public Flags.Load getLoad_flags() {
    return load_flags;
  }

















  /* ==================== setLoad_flags ================================== */
  public void setLoad_flags(Flags.Load load_flags) {
    this.load_flags = load_flags;
  }

  /* ==================== getGlyph_index ================================== */
  public int getGlyph_index() {
    return glyph_index;
  }







>
>
>







 







|







 







|


|
|



|







 







|
>







 







|





|







 







|







 







|
|







 







|
|









|







 







|







 







|







 







|







 







|







 







|













|
>
|
>
>
>
>
>







 







<





|







 







|







 







|







 







|







 







|







 







|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
...
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
...
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
...
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
...
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
...
764
765
766
767
768
769
770

771
772
773
774
775
776
777
778
779
780
781
782
783
...
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
...
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
...
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
...
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
....
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTStreamRec;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;
import org.apwtcl.apwfreetypelib.aftutil.TTUtil;

import java.util.HashSet;
import java.util.Set;

  /* ===================================================================== */
  /*    TTLoaderRec                                                          */
  /*                                                                       */
  /* ===================================================================== */

public class TTLoaderRec extends FTDebug {
................................................................................
  private int id;
  private static String TAG = "TTLoaderRec";

  private FTFaceRec face = null;
  private FTSizeRec size = null;
  private FTGlyphSlotRec glyph = null;
  private TTGlyphLoaderRec gloader = null;
  private Set<Flags.Load> load_flags = new HashSet<>();
  private int glyph_index = 0;
  private FTStreamRec stream = null;
  private int byte_len = 0;
  private int n_contours = 0;
  private FTBBoxRec bbox = null;
  private int left_bearing = 0;
  private int advance = 0;
................................................................................
    return str.toString();
  }

  /* =====================================================================
   * tt_loader_init
   * =====================================================================
   */
  public FTError.ErrorTag tt_loader_init(TTSizeRec size, FTGlyphSlotRec glyph, Set<Flags.Load> load_flags, boolean glyf_table_only) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_loader_init");
    TTFaceRec ttface;
    FTError.ErrorTag error;
    boolean pedantic = load_flags.contains(Flags.Load.PEDANTIC);

    ttface = (TTFaceRec)glyph.getFace();
    /* load execution context */
    if (!load_flags.contains(Flags.Load.NO_HINTING) && !glyf_table_only) {
      TTExecContextRec exec;
      boolean grayscale;
      boolean reexecute = false;

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "fill TTSizeRec\n");
      if (!size.isCvt_ready()) {
        error = size.tt_size_ready_bytecode(pedantic);
................................................................................
      /* query new execution context */

      exec = size.isDebug() ? size.getContext()
                         : ((TTDriverRec)ttface.getDriver()).context;
      if (exec == null) {
        return FTError.ErrorTag.GLYPH_COULD_NOT_FIND_CONTEXT;
      }
//      grayscale = (((load_flags.getVal() >> 16) & 15) != FTTags.RenderMode.MONO.getVal());
      grayscale = !load_flags.contains(Flags.Load.COLOR);
      exec.TTLoadContext(ttface, size);
      {
        /* a change from mono to grayscale rendering (and vice versa) */
        /* requires a re-execution of the CVT program                 */
        if (grayscale != exec.grayscale) {
          FTTrace.Trace(7, TAG, "tt_loader_init: grayscale change, re-executing `prep' table");
          exec.grayscale = grayscale;
................................................................................
        for (i = 0; i < size.getCvt_size(); i++) {
          size.getCvt()[i] = TTUtil.FTMulFix(ttface.getCvt_table().getCvtValue(i), size.getTtmetrics().getScale());
        }
        size.tt_size_run_prep(pedantic);
      }
      /* see whether the cvt program has disabled hinting */
      if ((exec.graphics_state.getInstruct_control() & 1) != 0) {
        load_flags.add(Flags.Load.NO_HINTING);
      }
      /* load default graphics state -- if needed */
      if ((exec.graphics_state.getInstruct_control() & 2) != 0) {
        exec.graphics_state = new TTDefaultGraphicsStateClass();
      }
      exec.pedantic_hinting = load_flags.contains(Flags.Load.PEDANTIC);
      this.exec = exec;
      this.base.setExec(exec);
      this.zone.setExec(exec);
      this.instructions = exec.glyphIns;
    }
    /* seek to the beginning of the glyph table -- for Type 42 fonts     */
    /* the table might be accessed from a Postscript stream or something */
................................................................................
      error = FTError.ErrorTag.GLYPH_INVALID_GLYPH_INDEX;
      if (opened_frame) {
        ttface.forgetGlyphFrame(this);
      }
      return error;
    }
    glyph_index = gindex;
    if (!load_flags.contains(Flags.Load.NO_SCALE)) {
      x_scale = size.getMetrics().getX_scale();
      y_scale = size.getMetrics().getY_scale();
    } else {
      x_scale = 0x10000;
      y_scale = 0x10000;
    }
    tt_get_metrics();
................................................................................
      pp1.setY(0);
      pp2.setX(pp1.getX() + advance);
      pp2.setY(0);
      pp3.setX(0);
      pp3.setY(top_bearing + bbox.getyMax());
      pp4.setX(0);
      pp4.setY(pp3.getY() - vadvance);
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader.pp1.x: %d %d %d %d", pp1.getX(), pp2.getX(), pp3.getY(), pp4.getY())+load_flags.contains(Flags.Load.NO_SCALE));
      if (!load_flags.contains(Flags.Load.NO_SCALE)) {
        pp1.setX(TTUtil.FTMulFix(pp1.getX(), x_scale));
        pp2.setX(TTUtil.FTMulFix(pp2.getX(), x_scale));
        pp3.setY(TTUtil.FTMulFix(pp3.getY(), y_scale));
        pp4.setY(TTUtil.FTMulFix(pp4.getY(), y_scale));
      }
      error = FTError.ErrorTag.ERR_OK;
      if (opened_frame) {
................................................................................
        }
        /* store the offset of instructions */
        ins_pos = this.ins_pos;
        /* all data we need are read */
        ttface.forgetGlyphFrame(this);
        opened_frame = false;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp4: loader.pp1.x: %d, loader.pp1.y: %d, loader.pp2.x: %d, loader.pp2.y: %d, loader.pp3.x: %d, loader.pp3.y: %d, loader.pp4.x: %d, loader.pp4.y: %d\n", pp1.getX(), pp1.getY(), pp2.getX(), pp2.getY(), pp3.getX(), pp3.getY(), pp4.getX(), pp4.getY()));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "LOAD_NO_SCALE: "+load_flags.contains(Flags.Load.NO_SCALE));
        if (!load_flags.contains(Flags.Load.NO_SCALE)) {
          pp1.setX(TTUtil.FTMulFix(pp1.getX(), x_scale));
          pp2.setX(TTUtil.FTMulFix(pp2.getX(), x_scale));
          pp3.setY(TTUtil.FTMulFix(pp3.getY(), y_scale));
          pp4.setY(TTUtil.FTMulFix(pp4.getY(), y_scale));
        }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp5: loader.pp1.x: %d, loader.pp1.y: %d, loader.pp2.x: %d, loader.pp2.y: %d, loader.pp3.x: %d, loader.pp3.y: %d, loader.pp4.x: %d, loader.pp4.y: %d\n", pp1.getX(), pp1.getY(), pp2.getX(), pp2.getY(), pp3.getX(), pp3.getY(), pp4.getX(), pp4.getY()));
        /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
        /* `as is' in the glyph slot (the client application will be     */
        /* responsible for interpreting these data)...                   */
        if (load_flags.contains(Flags.Load.NO_RECURSE)) {
          gloader.GlyphLoaderAdd();
          glyph.setFormat(FTTags.GlyphFormat.COMPOSITE);
          if (opened_frame) {
            ttface.forgetGlyphFrame(this);
          }
          return error;
        }
................................................................................
            /* (3): the newly loaded component                              */
            TTProcessCompositeComponent(subglyph, start_point, num_base_points);
          }
          stream = old_stream;
          byte_len = old_byte_len;
          /* process the glyph */
          this.ins_pos = ins_pos;
          if (load_flags.contains(Flags.Load.NO_HINTING) &&
                  ((subglyph.getFlags().getVal() & Flags.LoadType.WE_HAVE_INSTR.getVal()) != 0) && (num_points > start_point)) {
            TTProcessCompositeGlyph(start_point, start_contour);
          } 
        }
      } else {
      /* invalid composite count (negative but not -1) */
      error = FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
................................................................................

    int i;
    for (i = 0; i < gloader.getCurrent().getN_points() + 4; i++) {
//Debug(0, DBG_LOAD_GLYPH, TAG, String.format("PP2: i: %d x: %d y: %d\n", i, loader.gloader.current.outline.points[loader.gloader.current.outline.points_idx + i].x,
//loader.gloader.current.outline.points[loader.gloader.current.outline.points_idx + i].y));
    }
    y_scale = 0x10000;
    if (!load_flags.contains(Flags.Load.NO_SCALE)) {
      y_scale = ttsize.getMetrics().getY_scale();
    }
    if (glyph.getFormat().getVal() != FTTags.GlyphFormat.COMPOSITE.getVal()) {
      FTReference<FTBBoxRec> bbox_ref = new FTReference<FTBBoxRec>();
      bbox_ref.Set(new FTBBoxRec());
      glyph.getOutline().FTOutlineGetCBox(bbox_ref);
      bbox = bbox_ref.Get();
................................................................................
      /* by the base layer.                                                */
    glyph.setLinearHoriAdvance(linear);
    glyph.getMetrics().setHoriBearingX(bbox.getxMin());
    glyph.getMetrics().setHoriBearingY(bbox.getyMax());
    glyph.getMetrics().setHoriAdvance(pp2.getX() - pp1.getX());
      /* adjust advance width to the value contained in the hdmx table */
    if (ttface.getPostscript().getIsFixedPitch() != 0 &&
        (!load_flags.contains(Flags.Load.NO_HINTING))) {
      int widthpIdx;

      widthpIdx = TTLoad.tt_face_get_device_metrics(ttface, ttsize.getMetrics().getX_ppem(), glyph_index);
      if (widthpIdx != 0) {
        glyph.getMetrics().setHoriAdvance(ttface.getHdmx_table().getRecords()[widthpIdx] << 6);
      }
    }
................................................................................
        } else {
          advance = ttface.getHorizontal().getAscender() - ttface.getHorizontal().getDescender();
        }
        top = (advance - height) / 2;
      }
      glyph.setLinearVertAdvance(advance);
        /* scale the metrics */
      if (!load_flags.contains(Flags.Load.NO_SCALE)) {
        top = FTCalc.FTMulFix(top, y_scale);
        advance = FTCalc.FTMulFix(advance, y_scale);
      }
        /* XXX: for now, we have no better algorithm for the lsb, but it */
        /*      should work fine.                                        */
        /*                                                               */
      glyph.getMetrics().setVertBearingX(glyph.getMetrics().getHoriBearingX() -
................................................................................

      error = exec.TTSetCodeRange(TTInterpTags.CodeRange.GLYPH, exec.glyphIns, null, n_ins);
      if (error != FTError.ErrorTag.ERR_OK) {
        return error;
      }
      exec.is_composite = is_composite;
      exec.pts.copy(zone);
      debug = (!load_flags.contains(Flags.Load.NO_SCALE) && ((TTSizeRec)size).isDebug());
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "call TTRunContext");
if (gloader.getBase() != null) {
  gloader.getBase().showGloaderGlyph("base before call TTRunContext");
}
if (gloader.getCurrent() != null) {
  gloader.getCurrent().showGloaderGlyph("current before call TTRunContext");
}
zone.showLoaderZone("before call TTRunContext", exec);
      error = exec.TTRunContext(debug);
      if (error != FTError.ErrorTag.ERR_OK && exec.pedantic_hinting) {
        return error;
      }
        /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "scantype: 0x"+Integer.toHexString(exec.graphics_state.getScan_type()));
      current_outline.addTag(0, Flags.Curve.HAS_SCANMODE);
      if ((exec.graphics_state.getScan_type() & 1) != 0) {
        current_outline.addTag(0, Flags.Curve.TOUCH_X);
      }
      if ((exec.graphics_state.getScan_type() & 2) != 0) {
        current_outline.addTag(0, Flags.Curve.TOUCH_Y);
      }
    }
      /* save glyph phantom points */
    if (!preserve_pps) {
      pp1 = zone.getCurPoint(zone.getN_points() - 4);
      pp2 = zone.getCurPoint(zone.getN_points() - 3);
      pp3 = zone.getCurPoint(zone.getN_points() - 2);
      pp4 = zone.getCurPoint(zone.getN_points() - 1);
................................................................................
    int n_points;

    n_points = gloader.getCurrent().getN_points();
      /* set phantom points */
    gloader.getCurrent().setPoint(n_points, pp1);
    gloader.getCurrent().setPoint(n_points + 1, pp2);
    gloader.getCurrent().setPoint(n_points + 2, pp3);

    gloader.getCurrent().setTag(n_points, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 1, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 2, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 3, Flags.Curve.CONIC);
    n_points += 4;
    if (!load_flags.contains(Flags.Load.NO_HINTING)) {
      zone.tt_prepare_zone(gloader.getCurrent(), 0, 0);
      for (int i = 0; i < (zone.getN_points() + 4); i++) {
        zone.setOrusPoint(i, new FTVectorRec());
        zone.setOrusPoint_x(i, zone.getCurPoint_x(i));
        zone.setOrusPoint_y(i, zone.getCurPoint_y(i));
      }
    }
................................................................................
      int vecIdx = 0;
      int limit = n_points;
      int x_scale = 0; /* pacify compiler */
      int y_scale = 0;
      boolean do_scale = false;
      {
          /* scale the glyph */
        if (!load_flags.contains(Flags.Load.NO_SCALE)) {
          x_scale = size.getMetrics().getX_scale();
          y_scale = size.getMetrics().getY_scale();
          do_scale = true;
        }
      }
      if (do_scale) {
        for (vecIdx = 0; vecIdx < limit; vecIdx++) {
................................................................................
        }
        pp1 = gloader.getCurrent().getPoint(n_points - 4);
        pp2 = gloader.getCurrent().getPoint(n_points - 3);
        pp3 = gloader.getCurrent().getPoint(n_points - 2);
        pp4 = gloader.getCurrent().getPoint(n_points - 1);
      }
    }
    if (!load_flags.contains(Flags.Load.NO_HINTING)) {
      zone.setN_points(zone.getN_points() + 4);
      error = HintGlyph(false);
    }
    return error;
  }

  /* =====================================================================
................................................................................
          /* This algorithm is a guess and works much better than the above.       */
          /*                                                                       */
        int mac_xscale = FTCalc.FTHypot(subglyph.getTransform().getXx(), subglyph.getTransform().getXy());
        int mac_yscale = FTCalc.FTHypot(subglyph.getTransform().getYy(), subglyph.getTransform().getYx());
        x = TTUtil.FTMulFix(x, mac_xscale);
        y = TTUtil.FTMulFix(y, mac_yscale);
      }
      if (!load_flags.contains(Flags.Load.NO_SCALE)) {
        int x_scale = size.getMetrics().getX_scale();
        int y_scale = size.getMetrics().getY_scale();
        x = TTUtil.FTMulFix(x, x_scale);
        y = TTUtil.FTMulFix(y, y_scale);
        if ((subglyph.getFlags().getVal() & Flags.LoadType.ROUND_XY_TO_GRID.getVal()) != 0) {
          x = FTCalc.FT_PIX_ROUND(x);
          y = FTCalc.FT_PIX_ROUND(y);
................................................................................
      glyph.setControl_data(exec.glyphIns);
      glyph.setControl_len(n_ins);
    }
    zone.tt_prepare_zone(gloader.getBase(), start_point, start_contour);
      /* Some points are likely touched during execution of  */
      /* instructions on components.  So let's untouch them. */
    for (i = start_point; i < zone.getN_points(); i++) {
      zone.removeTag(i, Flags.Curve.TOUCH_BOTH);
    }
    zone.setN_points(zone.getN_points() + 4);
    return HintGlyph(true);
  }

  /* ==================== getFace ================================== */
  public FTFaceRec getFace() {
................................................................................

  /* ==================== setGloader ================================== */
  public void setGloader(TTGlyphLoaderRec gloader) {
    this.gloader = gloader;
  }

  /* ==================== getLoad_flags ================================== */
  public Set<Flags.Load> getLoad_flags() {
    return load_flags;
  }

  /* ==================== addLoad_flag ================================== */
  public void setLoad_flag(Flags.Load load_flag) {
    this.load_flags.clear();
    this.load_flags.add(load_flag);
  }

  /* ==================== addLoad_flag ================================== */
  public void addLoad_flag(Flags.Load load_flag) {
    this.load_flags.add(load_flag);
  }

  /* ==================== removeLoad_flag ================================== */
  public void removeLoad_flag(Flags.Load load_flag) {
    this.load_flags.remove(load_flag);
  }

  /* ==================== setLoad_flags ================================== */
  public void setLoad_flags(Set<Flags.Load> load_flags) {
    this.load_flags = load_flags;
  }

  /* ==================== getGlyph_index ================================== */
  public int getGlyph_index() {
    return glyph_index;
  }

Changes to afttruetype/TTSizeRec.java.

336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    if (ttface.getPrep_table().getPrepProgramSize() > 0) {
      error = (exec.TTGotoCodeRange(TTInterpTags.CodeRange.CVT, 0) == FTError.ErrorTag.ERR_OK ? FTError.ErrorTag.ERR_OK : FTError.ErrorTag.UNEXPECTED_NULL_VALUE);
      if (error == FTError.ErrorTag.ERR_OK && !debug) {
        FTTrace.Trace(7, TAG, "Executing `prep' table.");
        if (exec.code == null) {
          return FTError.ErrorTag.UNEXPECTED_NULL_VALUE;
        }
        for(int j = 0; j < 30 && j < exec.code.length; j++) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("j: %d 0x%02x ", j, exec.code[j].getVal())+exec.code[j]);
        }
        error = ttface.Interpreter(exec);
      }
    } else {
      error = FTError.ErrorTag.ERR_OK;
    }

      /* UNDOCUMENTED!  The MS rasterizer doesn't allow the following */







<
<
<







336
337
338
339
340
341
342



343
344
345
346
347
348
349
    if (ttface.getPrep_table().getPrepProgramSize() > 0) {
      error = (exec.TTGotoCodeRange(TTInterpTags.CodeRange.CVT, 0) == FTError.ErrorTag.ERR_OK ? FTError.ErrorTag.ERR_OK : FTError.ErrorTag.UNEXPECTED_NULL_VALUE);
      if (error == FTError.ErrorTag.ERR_OK && !debug) {
        FTTrace.Trace(7, TAG, "Executing `prep' table.");
        if (exec.code == null) {
          return FTError.ErrorTag.UNEXPECTED_NULL_VALUE;
        }



        error = ttface.Interpreter(exec);
      }
    } else {
      error = FTError.ErrorTag.ERR_OK;
    }

      /* UNDOCUMENTED!  The MS rasterizer doesn't allow the following */

Changes to aftttinterpreter/TTInstructionFuncGrp0.java.

260
261
262
263
264
265
266
267

268
269
270
271
272
273
274
      /* Cramer's rule */
    dbx = cur.zp0.getCurPoint_x(b1) - cur.zp0.getCurPoint_x(b0);
    dby = cur.zp0.getCurPoint_y(b1) - cur.zp0.getCurPoint_y(b0);
    dax = cur.zp1.getCurPoint_x(a1) - cur.zp1.getCurPoint_x(a0);
    day = cur.zp1.getCurPoint_y(a1) - cur.zp1.getCurPoint_y(a0);
    dx = cur.zp0.getCurPoint_x(b0) - cur.zp1.getCurPoint_x(a0);
    dy = cur.zp0.getCurPoint_y(b0) - cur.zp1.getCurPoint_y(a0);
    cur.zp2.getTags()[point] = Flags.Curve.getTableTag(cur.zp2.getTags()[point].getVal() | (Flags.Curve.TOUCH_X.getVal() | Flags.Curve.TOUCH_Y.getVal()));

    discriminant = FTCalc.FT_MulDiv(dax, -dby, 0x40) + FTCalc.FT_MulDiv(day, dbx, 0x40);
    dotproduct = FTCalc.FT_MulDiv(dax, dbx, 0x40) + FTCalc.FT_MulDiv(day, dby, 0x40);
      /* The discriminant above is actually a cross product of vectors     */
      /* da and db. Together with the dot product, they can be used as     */
      /* surrogates for sine and cosine of the angle between the vectors.  */
      /* Indeed,                                                           */
      /*       dotproduct   = |da||db|cos(angle)                           */







|
>







260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
      /* Cramer's rule */
    dbx = cur.zp0.getCurPoint_x(b1) - cur.zp0.getCurPoint_x(b0);
    dby = cur.zp0.getCurPoint_y(b1) - cur.zp0.getCurPoint_y(b0);
    dax = cur.zp1.getCurPoint_x(a1) - cur.zp1.getCurPoint_x(a0);
    day = cur.zp1.getCurPoint_y(a1) - cur.zp1.getCurPoint_y(a0);
    dx = cur.zp0.getCurPoint_x(b0) - cur.zp1.getCurPoint_x(a0);
    dy = cur.zp0.getCurPoint_y(b0) - cur.zp1.getCurPoint_y(a0);
    cur.zp2.addTag(point, Flags.Curve.TOUCH_X);
    cur.zp2.addTag(point, Flags.Curve.TOUCH_Y);
    discriminant = FTCalc.FT_MulDiv(dax, -dby, 0x40) + FTCalc.FT_MulDiv(day, dbx, 0x40);
    dotproduct = FTCalc.FT_MulDiv(dax, dbx, 0x40) + FTCalc.FT_MulDiv(day, dby, 0x40);
      /* The discriminant above is actually a cross product of vectors     */
      /* da and db. Together with the dot product, they can be used as     */
      /* surrogates for sine and cosine of the angle between the vectors.  */
      /* Indeed,                                                           */
      /*       dotproduct   = |da||db|cos(angle)                           */

Changes to aftttinterpreter/TTInstructionFuncGrp2.java.

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    point = (short)cur.stack[cur.stack_idx + 0];
    if (TTUtil.BOUNDS(point, cur.zp0.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    mask = (byte)0xFF;
    if (cur.graphics_state.freeVector.getX() != 0) {
      mask &= ~Flags.Curve.TOUCH_X.getVal();
    }
    if (cur.graphics_state.freeVector.getY() != 0) {
      mask &= ~Flags.Curve.TOUCH_Y.getVal();
    }
    cur.zp0.getTags()[point] = Flags.Curve.getTableTag(cur.zp0.getTags()[point].getVal() & mask);
  }

  /* =====================================================================
   * LOOPCALL[]:   LOOP and CALL function
   * Opcode range: 0x2A
   * Stack:        uint32? Eint16? -->
   * =====================================================================







<

|


|

<







240
241
242
243
244
245
246

247
248
249
250
251
252

253
254
255
256
257
258
259
    point = (short)cur.stack[cur.stack_idx + 0];
    if (TTUtil.BOUNDS(point, cur.zp0.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }

    if (cur.graphics_state.freeVector.getX() != 0) {
      cur.zp0.removeTag(point, Flags.Curve.TOUCH_X);
    }
    if (cur.graphics_state.freeVector.getY() != 0) {
      cur.zp0.removeTag(point, Flags.Curve.TOUCH_Y);
    }

  }

  /* =====================================================================
   * LOOPCALL[]:   LOOP and CALL function
   * Opcode range: 0x2A
   * Stack:        uint32? Eint16? -->
   * =====================================================================

Changes to aftttinterpreter/TTInstructionFuncGrp3.java.

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
...
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
   * MoveZp2Point
   * =====================================================================
   */
  private void MoveZp2Point(int point, int dx, int dy, boolean touch) {
    if (cur.graphics_state.freeVector.getX() != 0) {
      cur.zp2.setCurPoint_x(point, (cur.zp2.getCurPoint_x(point) + dx));
      if (touch) {
        cur.zp2.getTags()[point] = Flags.Curve.getTableTag(cur.zp2.getTags()[point].getVal() | Flags.Curve.TOUCH_X.getVal());
      }
    }
    if (cur.graphics_state.freeVector.getY() != 0) {
      cur.zp2.setCurPoint_y(point, (cur.zp2.getCurPoint_y(point) + dy));
      if (touch) {
        cur.zp2.getTags()[point] = Flags.Curve.getTableTag(cur.zp2.getTags()[point].getVal() | Flags.Curve.TOUCH_Y.getVal());
      }
    }
  }

  /* =====================================================================
   * IUP[a]:       Interpolate Untouched Points
   * Opcode range: 0x30-0x31
................................................................................
      V.setCur_idx(cur.pts.getCur_idx());
      V.setOrus(cur.pts.getOrus());
      V.setOrus_idx(cur.pts.getOrus_idx());
    } else {
      useX = false;
      mask = Flags.Curve.TOUCH_Y;
      V.setOrg(cur.pts.getOrg());
//        V.org_idx = cur.pts.org_idx + 1;
      V.setOrg_idx(cur.pts.getOrg_idx());
      V.setCur(cur.pts.getCur());
//        V.cur_idx = cur.pts.cur_idx + 1;
      V.setCur_idx(cur.pts.getCur_idx());
      V.setOrus(cur.pts.getOrus());
//        V.orus_idx = cur.pts.orus_idx + 1;
      V.setOrus_idx(cur.pts.getOrus_idx());
    }
    V.setMax_points(cur.pts.getN_points());
    contour = 0;
    point = 0;
    do {
      end_point = cur.pts.getContours()[contour] - cur.pts.getFirst_point();
      first_point = point;
      if (TTUtil.BOUNDS(end_point, cur.pts.getN_points())) {
        end_point = cur.pts.getN_points() - 1;
      }
      while (point <= end_point && (cur.pts.getTags()[point].getVal() & mask.getVal()) == 0) {
        point++;
      }
      worker_ref = new FTReference<>();
      worker_ref.Set(V);
      if (point <= end_point) {
        first_touched = point;
        cur_touched   = point;
        point++;
        while (point <= end_point) {
          if ((cur.pts.getTags()[point].getVal() & mask.getVal()) != 0) {
            _iup_worker_interpolate(worker_ref, cur_touched + 1, point - 1, cur_touched, point, useX);
            cur_touched = point;
          }
          point++;
        }
        if (cur_touched == first_touched) {
          _iup_worker_shift(worker_ref, first_point, end_point, cur_touched, useX);
................................................................................
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      cur.graphics_state.loop = 1;
      cur.new_top = cur.stack_idx;
      return;
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("twilight: %b, rp1: %d", twilight, cur.graphics_state.rp1));
    if (twilight) {
      orus_base = cur.zp0.getOrgPoint(cur.graphics_state.rp1);
    } else {
      orus_base = cur.zp0.getOrus()[cur.zp0.getOrus_idx() + cur.graphics_state.rp1];
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("orus.x: %d, orus.y: %d", orus_base.getX(),orus_base.getY()));
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("orus2.x: %d, orus2.y: %d", cur.zp0.getOrusPoint_x(1), cur.zp0.getOrusPoint(1)));
    }
    cur_base = cur.zp0.getCurPoint(cur.graphics_state.rp1);
      /* XXX: There are some glyphs in some braindead but popular */
      /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
      /*      calling IP[] with bad values of rp[12].             */
      /*      Do something sane when this odd thing happens.      */
    if (TTUtil.BOUNDS(cur.graphics_state.rp1, cur.zp0.getN_points()) || TTUtil.BOUNDS(cur.graphics_state.rp2, cur.zp1.getN_points())) {







|





|







 







<


<


<











|









|







 







|





|







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
...
296
297
298
299
300
301
302

303
304

305
306

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
   * MoveZp2Point
   * =====================================================================
   */
  private void MoveZp2Point(int point, int dx, int dy, boolean touch) {
    if (cur.graphics_state.freeVector.getX() != 0) {
      cur.zp2.setCurPoint_x(point, (cur.zp2.getCurPoint_x(point) + dx));
      if (touch) {
        cur.zp2.addTag(point, Flags.Curve.TOUCH_X);
      }
    }
    if (cur.graphics_state.freeVector.getY() != 0) {
      cur.zp2.setCurPoint_y(point, (cur.zp2.getCurPoint_y(point) + dy));
      if (touch) {
        cur.zp2.addTag(point, Flags.Curve.TOUCH_Y);
      }
    }
  }

  /* =====================================================================
   * IUP[a]:       Interpolate Untouched Points
   * Opcode range: 0x30-0x31
................................................................................
      V.setCur_idx(cur.pts.getCur_idx());
      V.setOrus(cur.pts.getOrus());
      V.setOrus_idx(cur.pts.getOrus_idx());
    } else {
      useX = false;
      mask = Flags.Curve.TOUCH_Y;
      V.setOrg(cur.pts.getOrg());

      V.setOrg_idx(cur.pts.getOrg_idx());
      V.setCur(cur.pts.getCur());

      V.setCur_idx(cur.pts.getCur_idx());
      V.setOrus(cur.pts.getOrus());

      V.setOrus_idx(cur.pts.getOrus_idx());
    }
    V.setMax_points(cur.pts.getN_points());
    contour = 0;
    point = 0;
    do {
      end_point = cur.pts.getContours()[contour] - cur.pts.getFirst_point();
      first_point = point;
      if (TTUtil.BOUNDS(end_point, cur.pts.getN_points())) {
        end_point = cur.pts.getN_points() - 1;
      }
      while (point <= end_point && !cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X)) {
        point++;
      }
      worker_ref = new FTReference<>();
      worker_ref.Set(V);
      if (point <= end_point) {
        first_touched = point;
        cur_touched   = point;
        point++;
        while (point <= end_point) {
          if (cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X)) {
            _iup_worker_interpolate(worker_ref, cur_touched + 1, point - 1, cur_touched, point, useX);
            cur_touched = point;
          }
          point++;
        }
        if (cur_touched == first_touched) {
          _iup_worker_shift(worker_ref, first_point, end_point, cur_touched, useX);
................................................................................
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      cur.graphics_state.loop = 1;
      cur.new_top = cur.stack_idx;
      return;
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("twilight: %b, rp1: ", twilight)+cur.graphics_state.rp1);
    if (twilight) {
      orus_base = cur.zp0.getOrgPoint(cur.graphics_state.rp1);
    } else {
      orus_base = cur.zp0.getOrus()[cur.zp0.getOrus_idx() + cur.graphics_state.rp1];
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("orus.x: %d, orus.y: %d", orus_base.getX(),orus_base.getY()));
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("orus2.x: %d, orus2.y: %d", cur.zp0.getOrusPoint_x(1), cur.zp0.getOrusPoint_y(1)));
    }
    cur_base = cur.zp0.getCurPoint(cur.graphics_state.rp1);
      /* XXX: There are some glyphs in some braindead but popular */
      /*      fonts out there (e.g. [aeu]grave in monotype.ttf)   */
      /*      calling IP[] with bad values of rp[12].             */
      /*      Do something sane when this odd thing happens.      */
    if (TTUtil.BOUNDS(cur.graphics_state.rp1, cur.zp0.getN_points()) || TTUtil.BOUNDS(cur.graphics_state.rp2, cur.zp1.getN_points())) {

Changes to aftttinterpreter/TTInstructionFuncGrp8.java.

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
..
80
81
82
83
84
85
86
87




88
89
90
91
92
93
94
..
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  /* =====================================================================
   * FLIPPT[]:     FLIP PoinT
   * Opcode range: 0x80
   * Stack:        uint32... -->
   * =====================================================================
   */
  public void FLIPPT() {
    short point;

    if (cur.top < cur.graphics_state.loop) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_TOO_FEW_ARGUMENTS;
      }
      cur.graphics_state.loop = 1;
      cur.new_top = cur.stack_idx;
................................................................................
      point = (short)cur.stack[cur.stack_idx];
      if (TTUtil.BOUNDS(point, cur.pts.getN_points())) {
        if (cur.pedantic_hinting) {
          cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
          return;
        }
      } else {
        cur.pts.getTags()[point] = Flags.Curve.getTableTag(cur.pts.getTags()[point].getVal() ^ Flags.Curve.ON.getVal());




      }
      cur.graphics_state.loop--;
    }
    cur.graphics_state.loop = 1;
    cur.new_top = cur.stack_idx;
  }

................................................................................
  /* =====================================================================
   * FLIPRGON[]:   FLIP RanGe ON
   * Opcode range: 0x81
   * Stack:        uint32 uint32 -->
   * =====================================================================
   */
  public void FLIPRGON() {
    short I;
    short K;
    short L;

    K = (short)cur.stack[cur.stack_idx + 1];
    L = (short)cur.stack[cur.stack_idx + 0];
    if (TTUtil.BOUNDS(K, cur.pts.getN_points()) || TTUtil.BOUNDS(L, cur.pts.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    for (I = L; I <= K; I++) {
      cur.pts.getTags()[I] = Flags.Curve.getTableTag(cur.pts.getTags()[I].getVal() | Flags.Curve.ON.getVal());
    }
  }

  /* =====================================================================
   * FLIPRGOFF:    FLIP RanGe OFF
   * Opcode range: 0x82
   * Stack:        uint32 uint32 -->
   * =====================================================================
   */
  public void FLIPRGOFF() {
    short I;
    short K;
    short L;

    K = (short)cur.stack[cur.stack_idx + 1];
    L = (short)cur.stack[cur.stack_idx + 0];
    if (TTUtil.BOUNDS(K, cur.pts.getN_points()) || TTUtil.BOUNDS(L, cur.pts.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    for (I = L; I <= K; I++) {
      cur.pts.getTags()[I] = Flags.Curve.getTableTag(cur.pts.getTags()[I].getVal() & ~Flags.Curve.ON.getVal());
    }
  }

  /* =====================================================================
   * SCANCTRL[]:   SCAN ConTRoL
   * Opcode range: 0x85
   * Stack:        uint32? -->







|







 







|
>
>
>
>







 







|
|
|

|
|
|





|
|










|
|
|

|
|
|





|
|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
..
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  /* =====================================================================
   * FLIPPT[]:     FLIP PoinT
   * Opcode range: 0x80
   * Stack:        uint32... -->
   * =====================================================================
   */
  public void FLIPPT() {
    int point;

    if (cur.top < cur.graphics_state.loop) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_TOO_FEW_ARGUMENTS;
      }
      cur.graphics_state.loop = 1;
      cur.new_top = cur.stack_idx;
................................................................................
      point = (short)cur.stack[cur.stack_idx];
      if (TTUtil.BOUNDS(point, cur.pts.getN_points())) {
        if (cur.pedantic_hinting) {
          cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
          return;
        }
      } else {
        if (cur.pts.getTag(point).contains(Flags.Curve.ON)) {
          cur.pts.removeTag(point, Flags.Curve.ON);
        } else {
          cur.pts.addTag(point, Flags.Curve.ON);
        }
      }
      cur.graphics_state.loop--;
    }
    cur.graphics_state.loop = 1;
    cur.new_top = cur.stack_idx;
  }

................................................................................
  /* =====================================================================
   * FLIPRGON[]:   FLIP RanGe ON
   * Opcode range: 0x81
   * Stack:        uint32 uint32 -->
   * =====================================================================
   */
  public void FLIPRGON() {
    int idx;
    int end_idx;
    int start_idx;

    end_idx = cur.stack[cur.stack_idx + 1];
    start_idx = cur.stack[cur.stack_idx];
    if (TTUtil.BOUNDS(end_idx, cur.pts.getN_points()) || TTUtil.BOUNDS(start_idx, cur.pts.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    for (idx = start_idx; idx <= end_idx; idx++) {
      cur.pts.addTag(idx, Flags.Curve.ON);
    }
  }

  /* =====================================================================
   * FLIPRGOFF:    FLIP RanGe OFF
   * Opcode range: 0x82
   * Stack:        uint32 uint32 -->
   * =====================================================================
   */
  public void FLIPRGOFF() {
    int idx;
    int end_idx;
    int start_idx;

    end_idx = cur.stack[cur.stack_idx + 1];
    start_idx = cur.stack[cur.stack_idx];
    if (TTUtil.BOUNDS(end_idx, cur.pts.getN_points()) || TTUtil.BOUNDS(start_idx, cur.pts.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    for (idx = start_idx; idx <= end_idx; idx++) {
      cur.pts.removeTag(idx, Flags.Curve.ON);
    }
  }

  /* =====================================================================
   * SCANCTRL[]:   SCAN ConTRoL
   * Opcode range: 0x85
   * Stack:        uint32? -->

Changes to aftttinterpreter/TTInstructionFuncGrp9.java.

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


75
76
77
78
79
80
81
82
83
84
85
86
87
..
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  /* =====================================================================
   * MIRP[abcde]:  Move Indirect Relative Point
   * Opcode range: 0xE0-0xFF
   * Stack:        int32? uint32 -->
   * =====================================================================
   */
  public void MIRP() {
    short point;
    int cvtEntry;
    int cvt_dist;
    int distance;
    int cur_dist;
    int org_dist;
    int control_value_cutin;
    int minimum_distance;



    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Ins_MIRP: cur.GS.rp0: %d, cur.GS.rp1: %d", cur.graphics_state.rp0, cur.graphics_state.rp1));
    minimum_distance = cur.graphics_state.minimum_distance;
    control_value_cutin = cur.graphics_state.control_value_cutin;
    point = (short)cur.stack[cur.stack_idx + 0];
    cvtEntry = cur.stack[cur.stack_idx + 1] + 1;
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Ins_MIRP: minimum_distance: %d, control_value_cutin: %d, point: %d, cvtEntry: %d", minimum_distance, control_value_cutin, point, cvtEntry));
      /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
    if (TTUtil.BOUNDS(point, cur.zp1.getN_points()) ||
        TTUtil.BOUNDSL(cvtEntry, cur.cvtSize + 1) ||
        TTUtil.BOUNDS(cur.graphics_state.rp0, cur.zp0.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
................................................................................
      return;
    }
    if (cvtEntry == 0) {
      cvt_dist = 0;
    } else {
      cvt_dist = cur.render_funcs.curr_cvt_func.readCvt(cvtEntry - 1);
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("cvtEntry: %d, cvt_dist: %d", cvtEntry, cvt_dist));
      /* single width test */
    if (FTCalc.FT_ABS(cvt_dist - cur.graphics_state.single_width_value) < cur.graphics_state.single_width_cutin) {
      if (cvt_dist >= 0) {
        cvt_dist = cur.graphics_state.single_width_value;
      } else {
        cvt_dist = -cur.graphics_state.single_width_value;
      }
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("cvt_dist: %d, cur.GS.gep0: %d, cur.GS.gep1: %d", cvt_dist, cur.graphics_state.gep0, cur.graphics_state.gep1));
      /* UNDOCUMENTED!  The MS rasterizer does that with */
      /* twilight points (confirmed by Greg Hitchcock)   */
    if (cur.graphics_state.gep1 == 0) {
      cur.zp1.setOrgPoint_x(point, (cur.zp0.getOrgPoint_x(cur.graphics_state.rp0) + TTUtil.TTMulFix14(cvt_dist, cur.graphics_state.freeVector.getX())));
      cur.zp1.setOrgPoint_y(point, (cur.zp0.getOrgPoint_y(cur.graphics_state.rp0) + TTUtil.TTMulFix14(cvt_dist, cur.graphics_state.freeVector.getY())));
      cur.zp1.setCurPoint(point, cur.zp1.getOrgPoint(point));
    }







|








>
>
|


|

|







 







|








|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  /* =====================================================================
   * MIRP[abcde]:  Move Indirect Relative Point
   * Opcode range: 0xE0-0xFF
   * Stack:        int32? uint32 -->
   * =====================================================================
   */
  public void MIRP() {
    int point;
    int cvtEntry;
    int cvt_dist;
    int distance;
    int cur_dist;
    int org_dist;
    int control_value_cutin;
    int minimum_distance;

//cur.zp0.showLoaderZone("zp0", cur);
//cur.zp1.showLoaderZone("zp1", cur);
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("MIRP: cur.GS.rp0: %d, cur.GS.rp1: %d", cur.graphics_state.rp0, cur.graphics_state.rp1));
    minimum_distance = cur.graphics_state.minimum_distance;
    control_value_cutin = cur.graphics_state.control_value_cutin;
    point = cur.stack[cur.stack_idx];
    cvtEntry = cur.stack[cur.stack_idx + 1] + 1;
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("MIRP: minimum_distance: %d, control_value_cutin: %d, point: %d, cvtEntry: %d", minimum_distance, control_value_cutin, point, cvtEntry));
      /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
    if (TTUtil.BOUNDS(point, cur.zp1.getN_points()) ||
        TTUtil.BOUNDSL(cvtEntry, cur.cvtSize + 1) ||
        TTUtil.BOUNDS(cur.graphics_state.rp0, cur.zp0.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
................................................................................
      return;
    }
    if (cvtEntry == 0) {
      cvt_dist = 0;
    } else {
      cvt_dist = cur.render_funcs.curr_cvt_func.readCvt(cvtEntry - 1);
    }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("cvtEntry: %d, cvt_dist: %d", cvtEntry, cvt_dist));
      /* single width test */
    if (FTCalc.FT_ABS(cvt_dist - cur.graphics_state.single_width_value) < cur.graphics_state.single_width_cutin) {
      if (cvt_dist >= 0) {
        cvt_dist = cur.graphics_state.single_width_value;
      } else {
        cvt_dist = -cur.graphics_state.single_width_value;
      }
    }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("cvt_dist: %d, cur.GS.gep0: %d, cur.GS.gep1: %d", cvt_dist, cur.graphics_state.gep0, cur.graphics_state.gep1));
      /* UNDOCUMENTED!  The MS rasterizer does that with */
      /* twilight points (confirmed by Greg Hitchcock)   */
    if (cur.graphics_state.gep1 == 0) {
      cur.zp1.setOrgPoint_x(point, (cur.zp0.getOrgPoint_x(cur.graphics_state.rp0) + TTUtil.TTMulFix14(cvt_dist, cur.graphics_state.freeVector.getX())));
      cur.zp1.setOrgPoint_y(point, (cur.zp0.getOrgPoint_y(cur.graphics_state.rp0) + TTUtil.TTMulFix14(cvt_dist, cur.graphics_state.freeVector.getY())));
      cur.zp1.setCurPoint(point, cur.zp1.getOrgPoint(point));
    }

Changes to aftttinterpreter/TTMoveFunc.java.

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
    int v;
    Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMove");
    v = cur.graphics_state.freeVector.getX();
    if (v != 0) {
      zone.setCurPoint_x(point,  zone.getCurPoint_x(point) + FTCalc.FT_MulDiv(distance, v, cur.F_dot_P));
      zone.getTags()[point] = Flags.Curve.getTableTag(zone.getTags()[point].getVal() | Flags.Curve.TOUCH_X.getVal());
    }
    v = cur.graphics_state.freeVector.getY();
    if (v != 0) {
      zone.setCurPoint_y(point, zone.getCurPoint_y(point) + FTCalc.FT_MulDiv(distance, v, cur.F_dot_P));
      zone.getTags()[point] = Flags.Curve.getTableTag(zone.getTags()[point].getVal() | Flags.Curve.TOUCH_Y.getVal());
    }
  }

  /* =====================================================================
   * DirectMoveOrig
   *
   * =====================================================================







|




|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
    int v;
    Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMove");
    v = cur.graphics_state.freeVector.getX();
    if (v != 0) {
      zone.setCurPoint_x(point,  zone.getCurPoint_x(point) + FTCalc.FT_MulDiv(distance, v, cur.F_dot_P));
      zone.addTag(point, Flags.Curve.TOUCH_X);
    }
    v = cur.graphics_state.freeVector.getY();
    if (v != 0) {
      zone.setCurPoint_y(point, zone.getCurPoint_y(point) + FTCalc.FT_MulDiv(distance, v, cur.F_dot_P));
      zone.addTag(point, Flags.Curve.TOUCH_Y);
    }
  }

  /* =====================================================================
   * DirectMoveOrig
   *
   * =====================================================================

Changes to aftttinterpreter/TTMoveXFunc.java.

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  /* ==================== move ===================================== */
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMoveX");
//    FTGlyphLoaderRec._showLoaderZone("DirectMoveX");
Debug(0, DebugTag.DBG_INTERP, TAG, "zone: "+zone.toDebugString()+"!");
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Direct_Move_X: point: %d x: %d distance: %d\n", point, zone.getCurPoint_x(point), distance));
    zone.setCurPoint_y(point, zone.getCurPoint_y(point) + distance);
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Direct_Move_X2: cur_idx: %d point: %d x: %d distance: %d\n",
        zone.getCur_idx(), point, zone.getCurPoint_x(point), distance));
    zone.getTags()[point] = Flags.Curve.getTableTag(zone.getTags()[point].getVal() | Flags.Curve.TOUCH_X.getVal());
  }

  /* =====================================================================
   * DirectMoveOrigX
   *
   * =====================================================================
   */







|


|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  /* ==================== move ===================================== */
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMoveX");
//    FTGlyphLoaderRec._showLoaderZone("DirectMoveX");
Debug(0, DebugTag.DBG_INTERP, TAG, "zone: "+zone.toDebugString()+"!");
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Direct_Move_X: point: %d x: %d distance: %d\n", point, zone.getCurPoint_x(point), distance));
    zone.setCurPoint_x(point, zone.getCurPoint_x(point) + distance);
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Direct_Move_X2: cur_idx: %d point: %d x: %d distance: %d\n",
        zone.getCur_idx(), point, zone.getCurPoint_x(point), distance));
    zone.addTag(point, Flags.Curve.TOUCH_X);
  }

  /* =====================================================================
   * DirectMoveOrigX
   *
   * =====================================================================
   */

Changes to aftttinterpreter/TTMoveYFunc.java.

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
   */
  /* ==================== move ===================================== */
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMoveY");
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Direct_Move_Y: %d %d %d\n", point, zone.getCurPoint_y(point), distance));
    zone.setCurPoint_y(point, zone.getCurPoint_y(point) + distance);
    zone.getTags()[point] = Flags.Curve.getTableTag(zone.getTags()[point].getVal() | Flags.Curve.TOUCH_Y.getVal());
  }

  /* =====================================================================
   * DirectMoveOrigY
   *
   * =====================================================================
   */







|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
   */
  /* ==================== move ===================================== */
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMoveY");
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("Direct_Move_Y: %d %d %d\n", point, zone.getCurPoint_y(point), distance));
    zone.setCurPoint_y(point, zone.getCurPoint_y(point) + distance);
    zone.addTag(point, Flags.Curve.TOUCH_Y);
  }

  /* =====================================================================
   * DirectMoveOrigY
   *
   * =====================================================================
   */

Changes to aftttinterpreter/TTProjectXFunc.java.

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
   *    The distance in F26dot6 format.
   *
   * =====================================================================
   */
  /* ==================== project ===================================== */
  @Override
  public int project(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("ProjectX: dx: %d, dy: %d", dx, dy));
    return dx;
  }

  /* ==================== dualproject ===================================== */
  @Override
  public int dualproject(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, "DualProject");
    return project(dx, dy);
  }

}







|











62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
   *    The distance in F26dot6 format.
   *
   * =====================================================================
   */
  /* ==================== project ===================================== */
  @Override
  public int project(int dx, int dy) {
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("ProjectX: dx: %d, dy: %d", dx, dy));
    return dx;
  }

  /* ==================== dualproject ===================================== */
  @Override
  public int dualproject(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, "DualProject");
    return project(dx, dy);
  }

}

Changes to aftttinterpreter/TTRoundToGridFunc.java.

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
   *
   * =====================================================================
   */
  /* ==================== round ===================================== */
  @Override
  public int round(int distance, int compensation) {
    int val;
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("RoundToGrid: distance: %d, compensation: %d", distance, compensation));

    if (distance >= 0) {
      val = distance + compensation + 32;
      if (distance != 0 && val > 0) {
        val &= ~63;
      } else {
        val = 0;







|







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
   *
   * =====================================================================
   */
  /* ==================== round ===================================== */
  @Override
  public int round(int distance, int compensation) {
    int val;
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("RoundToGrid: distance: %d, compensation: %d", distance, compensation));

    if (distance >= 0) {
      val = distance + compensation + 32;
      if (distance != 0 && val > 0) {
        val &= ~63;
      } else {
        val = 0;

Changes to aftttinterpreter/TTRunInstructions.java.

682
683
684
685
686
687
688

689



690
691
692
693
694
695
696
          }
            /* increment instruction counter and check if we didn't */
            /* run this program for too long (e.g. infinite loops). */
          if (++ins_counter > MAX_RUNNABLE_OPCODES) {
            return FTError.ErrorTag.INTERP_EXECUTION_TOO_LONG;
          }
        }

//Debug(0, DBG_INTERP, TAG, String.format("ll4: %d %d", cur.IP, cur.codeSize));



//        showLoaderZone();
        if (IP >= codeSize) {
          if (callTop > 0) {
            error = FTError.ErrorTag.INTERP_CODE_OVERFLOW;
            return LError();
          } else {
            return FTError.ErrorTag.ERR_OK;







>
|
>
>
>







682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
          }
            /* increment instruction counter and check if we didn't */
            /* run this program for too long (e.g. infinite loops). */
          if (++ins_counter > MAX_RUNNABLE_OPCODES) {
            return FTError.ErrorTag.INTERP_EXECUTION_TOO_LONG;
          }
        }
if (numInstructions > 6000) {
  Debug(0, DebugTag.DBG_INTERP, TAG, String.format("ll4: %d %d", IP, codeSize));
  zp0.showLoaderZone("ZP0", this);
  zp2.showLoaderZone("ZP1", this);
}
//        showLoaderZone();
        if (IP >= codeSize) {
          if (callTop > 0) {
            error = FTError.ErrorTag.INTERP_CODE_OVERFLOW;
            return LError();
          } else {
            return FTError.ErrorTag.ERR_OK;

Changes to aftutil/FTUtil.java.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

package org.apwtcl.apwfreetypelib.aftutil;

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.FTCharMapRec;
import org.apwtcl.apwfreetypelib.aftbase.Flags;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

  /* ===================================================================== */
  /*    FTUtil                                                          */
  /*                                                                       */
  /* ===================================================================== */

public class FTUtil extends FTDebug {
................................................................................
                }
                obj = byte_array;
              }
            }
          }
          break;
        case CURVE:
          Flags.Curve[] curve_array = (Flags.Curve[]) obj;
          if (curve_array == null) {
            // easy just allocate
            curve_array = new Flags.Curve[newCount];
            for (i = 0; i < newCount; i++) {
              curve_array[i] = Flags.Curve.CONIC;
            }
            obj = curve_array;
          } else {
            if (curve_array.length >= newCount) {
              // nothing to do
            } else {
              if (curCount == 0) {
                curve_array = new Flags.Curve[newCount];
                for (j = 0; j < newCount; j++) {
                  curve_array[j] = Flags.Curve.CONIC;
                }
                obj = curve_array;
              } else {
                Flags.Curve[] tmp2;
                tmp2 = java.util.Arrays.copyOf(curve_array, curCount);
                curve_array = new Flags.Curve[newCount];
                for (k = 0; k < curCount; k++) {
                  curve_array[k] = tmp2[k];
                }
                for (k = curCount; k < newCount; k++) {
                  curve_array[k] = Flags.Curve.CONIC;
                }
                obj = curve_array;
              }
            }
          }
          break;
        case SHORT:







|
|
|







 







|


|

|







|

|



|

|




|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

package org.apwtcl.apwfreetypelib.aftutil;

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.FTCharMapRec;
import org.apwtcl.apwfreetypelib.aftbase.Flags;

import java.util.HashSet;
import java.util.Set;

  /* ===================================================================== */
  /*    FTUtil                                                          */
  /*                                                                       */
  /* ===================================================================== */

public class FTUtil extends FTDebug {
................................................................................
                }
                obj = byte_array;
              }
            }
          }
          break;
        case CURVE:
          Set<Flags.Curve>[] curve_array = (Set<Flags.Curve>[]) obj;
          if (curve_array == null) {
            // easy just allocate
            curve_array = new Set[newCount];
            for (i = 0; i < newCount; i++) {
              curve_array[i] = new HashSet<>();
            }
            obj = curve_array;
          } else {
            if (curve_array.length >= newCount) {
              // nothing to do
            } else {
              if (curCount == 0) {
                curve_array = new Set[newCount];
                for (j = 0; j < newCount; j++) {
                  curve_array[j] = new HashSet<>();
                }
                obj = curve_array;
              } else {
                Set<Flags.Curve>[] tmp2;
                tmp2 = java.util.Arrays.copyOf(curve_array, curCount);
                curve_array = new Set[newCount];
                for (k = 0; k < curCount; k++) {
                  curve_array[k] = tmp2[k];
                }
                for (k = curCount; k < newCount; k++) {
                  curve_array[k] = new HashSet<>();
                }
                obj = curve_array;
              }
            }
          }
          break;
        case SHORT: