apwfreetypelib

Check-in [064b26a0cc]
Login

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

Overview
Comment:fixes, new code and refactoring.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:064b26a0ccfb72704d6ee802ed262dce5f59c60f
User & Date: arnulf 2015-01-25 21:10:37
Context
2015-01-31
21:35
fixes. check-in: 41fd1a1418 user: arnulf tags: trunk
2015-01-25
21:10
fixes, new code and refactoring. check-in: 064b26a0cc user: arnulf tags: trunk
18:58
fixes and new code. check-in: c443e0dd64 user: arnulf tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to aftbase/FTBitmapGlyphRec.java.

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    error = glyphPrepare(this, dummy_ref);
    dummy = dummy_ref.Get();
    if (error == FTError.ErrorTag.ERR_OK) {
      error = dummy.FTRenderGlyphInternal(this.library, render_mode);
    }
    if (destroy && origin != null) {
      FTVectorRec v = new FTVectorRec();
      v.x = -origin.x;
      v.y = -origin.y;
      GlyphTransform(this, 0, v);
    }
    if (error != FTError.ErrorTag.ERR_OK) {
      if (error != FTError.ErrorTag.ERR_OK && bitmap != null) {
// FIXME FTDoneGlyph
//      	FTGlyphLoaderRec.FTDoneGlyph((FTGlyphRec)bitmap);
      }







|
|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    error = glyphPrepare(this, dummy_ref);
    dummy = dummy_ref.Get();
    if (error == FTError.ErrorTag.ERR_OK) {
      error = dummy.FTRenderGlyphInternal(this.library, render_mode);
    }
    if (destroy && origin != null) {
      FTVectorRec v = new FTVectorRec();
      v.setX(-origin.getX());
      v.setY(-origin.getY());
      GlyphTransform(this, 0, v);
    }
    if (error != FTError.ErrorTag.ERR_OK) {
      if (error != FTError.ErrorTag.ERR_OK && bitmap != null) {
// FIXME FTDoneGlyph
//      	FTGlyphLoaderRec.FTDoneGlyph((FTGlyphRec)bitmap);
      }

Changes to aftbase/FTDriverClassRec.java.

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }

  /* ==================== initFace ===================================== */
  public FTError.ErrorTag initFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params,
        FTParameter[] params) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Log.e(TAG, "initFace not yet implemented");
    return error;
  }

  /* ==================== doneFace ===================================== */







|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }

  /* ==================== initFace ===================================== */
  public FTError.ErrorTag initFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params,
        FTParameterRec[] params) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Log.e(TAG, "initFace not yet implemented");
    return error;
  }

  /* ==================== doneFace ===================================== */

Changes to aftbase/FTFaceRec.java.

247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  }

  /* =====================================================================
   * FTNewFace
   * =====================================================================
   */
  public static FTError.ErrorTag FTNewFace(FTLibraryRec library, String pathname, int face_index, FTReference<FTFaceRec> face_ref) {
    FTOpenArgs args = new FTOpenArgs();
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "FTNewFace: pathname: "+pathname+"!");
    /* test for valid `library' and `face_ref' delayed to FT_Open_Face() */
    if (pathname == null) {
      Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "FTNewFace1 inv arg");
      return FTError.ErrorTag.INTERP_INVALID_ARGUMENT;
................................................................................
  }

  /* =====================================================================
   * open_face
   * =====================================================================
   */
  public FTError.ErrorTag open_face(FTDriverRec driver, FTStreamRec stream, int face_index, int num_params,
                                           FTParameter[] params) {
    FTDriverClassRec clazz;
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTError.ErrorTag error2 = FTError.ErrorTag.ERR_OK;

    FTTrace.Trace(7, TAG, "open_face");
    clazz  = driver.getDriver_clazz();
    this.driver = driver;
................................................................................
    return error;
  }

  /* =====================================================================
   * FTOpenFace
   * =====================================================================
   */
  public static FTError.ErrorTag FTOpenFace(FTLibraryRec library, FTOpenArgs args, int face_index, FTReference<FTFaceRec> face_ref) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTDriverRec driver = null;
    FTReference<RandomAccessFile> stream_ref = new FTReference<RandomAccessFile>();
    FTFaceRec face = null;
    FTListNodeRec node = null;
    boolean is_external_stream;
    FTModuleRec cur;
................................................................................
    /* If the font driver is specified in the `args' structure, use */
    /* it.  Otherwise, we scan the list of registered drivers.      */
    if (FTUtilFlags.StreamOpen.isDriver(args.getFlags()) && args.getDriver() != null) {
      driver = (TTDriverRec)args.getDriver();
      /* not all modules are drivers, so check... */
      if ((driver.getDriver_clazz().module_flags & Flags.Module.FONT_DRIVER.getVal()) != 0) {
        int num_params = 0;
        FTParameter[] params =null ;

        if (FTUtilFlags.StreamOpen.isParams(args.getFlags())) {
          num_params = args.getNum_params();
          params = args.getParams();
        }
        /* allocate the face object and perform basic initialization */
        switch (driver.getDriver_clazz().getFaceObjectType()) {
................................................................................
        /* check each font driver for an appropriate format */
      limit = library.getNum_modules();
      for (module_idx = 0; module_idx < limit; module_idx++) {
        cur = library.getModule(module_idx);
          /* not all modules are font drivers, so check... */
        if ((cur.module_clazz.module_flags & Flags.Module.FONT_DRIVER.getVal()) != 0) {
          int num_params = 0;
          FTParameter params[] = null;

          TTDriverRec cur_obj = (TTDriverRec)library.getModule(module_idx);
          driver = cur_obj;
          if (FTUtilFlags.StreamOpen.isParams(args.getFlags())) {
            num_params = args.getNum_params();
            params = args.getParams();
          }
................................................................................
        if (bsize.y_ppem < 0) {
          bsize.y_ppem = -bsize.y_ppem;
        }
      }
    }
      /* initialize internal face data */
    {
      face.internal.getTransform_matrix().xx = 0x10000;
      face.internal.getTransform_matrix().xy = 0;
      face.internal.getTransform_matrix().yx = 0;
      face.internal.getTransform_matrix().yy = 0x10000;
      face.internal.getTransform_delta().x = 0;
      face.internal.getTransform_delta().y = 0;
      face.internal.setRefcount(1);
    }
    if (face_ref != null) {
      face_ref.Set(face);
    } else {
//        FTDoneFace(face);
    }







|







 







|







 







|







 







|







 







|







 







|
|
|
|
|
|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
...
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  }

  /* =====================================================================
   * FTNewFace
   * =====================================================================
   */
  public static FTError.ErrorTag FTNewFace(FTLibraryRec library, String pathname, int face_index, FTReference<FTFaceRec> face_ref) {
    FTOpenArgsRec args = new FTOpenArgsRec();
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "FTNewFace: pathname: "+pathname+"!");
    /* test for valid `library' and `face_ref' delayed to FT_Open_Face() */
    if (pathname == null) {
      Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "FTNewFace1 inv arg");
      return FTError.ErrorTag.INTERP_INVALID_ARGUMENT;
................................................................................
  }

  /* =====================================================================
   * open_face
   * =====================================================================
   */
  public FTError.ErrorTag open_face(FTDriverRec driver, FTStreamRec stream, int face_index, int num_params,
                                           FTParameterRec[] params) {
    FTDriverClassRec clazz;
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTError.ErrorTag error2 = FTError.ErrorTag.ERR_OK;

    FTTrace.Trace(7, TAG, "open_face");
    clazz  = driver.getDriver_clazz();
    this.driver = driver;
................................................................................
    return error;
  }

  /* =====================================================================
   * FTOpenFace
   * =====================================================================
   */
  public static FTError.ErrorTag FTOpenFace(FTLibraryRec library, FTOpenArgsRec args, int face_index, FTReference<FTFaceRec> face_ref) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTDriverRec driver = null;
    FTReference<RandomAccessFile> stream_ref = new FTReference<RandomAccessFile>();
    FTFaceRec face = null;
    FTListNodeRec node = null;
    boolean is_external_stream;
    FTModuleRec cur;
................................................................................
    /* If the font driver is specified in the `args' structure, use */
    /* it.  Otherwise, we scan the list of registered drivers.      */
    if (FTUtilFlags.StreamOpen.isDriver(args.getFlags()) && args.getDriver() != null) {
      driver = (TTDriverRec)args.getDriver();
      /* not all modules are drivers, so check... */
      if ((driver.getDriver_clazz().module_flags & Flags.Module.FONT_DRIVER.getVal()) != 0) {
        int num_params = 0;
        FTParameterRec[] params =null ;

        if (FTUtilFlags.StreamOpen.isParams(args.getFlags())) {
          num_params = args.getNum_params();
          params = args.getParams();
        }
        /* allocate the face object and perform basic initialization */
        switch (driver.getDriver_clazz().getFaceObjectType()) {
................................................................................
        /* check each font driver for an appropriate format */
      limit = library.getNum_modules();
      for (module_idx = 0; module_idx < limit; module_idx++) {
        cur = library.getModule(module_idx);
          /* not all modules are font drivers, so check... */
        if ((cur.module_clazz.module_flags & Flags.Module.FONT_DRIVER.getVal()) != 0) {
          int num_params = 0;
          FTParameterRec params[] = null;

          TTDriverRec cur_obj = (TTDriverRec)library.getModule(module_idx);
          driver = cur_obj;
          if (FTUtilFlags.StreamOpen.isParams(args.getFlags())) {
            num_params = args.getNum_params();
            params = args.getParams();
          }
................................................................................
        if (bsize.y_ppem < 0) {
          bsize.y_ppem = -bsize.y_ppem;
        }
      }
    }
      /* initialize internal face data */
    {
      face.internal.getTransform_matrix().setXx(0x10000);
      face.internal.getTransform_matrix().setXy(0);
      face.internal.getTransform_matrix().setYx(0);
      face.internal.getTransform_matrix().setYy(0x10000);
      face.internal.getTransform_delta().setX(0);
      face.internal.getTransform_delta().setY(0);
      face.internal.setRefcount(1);
    }
    if (face_ref != null) {
      face_ref.Set(face);
    } else {
//        FTDoneFace(face);
    }

Changes to aftbase/FTGlyphLoadRec.java.

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "loaderLoad.extra_points2: "+extra_points2+"!"+extra_points2_idx);
    }
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "Show loaderLoad");
    for (j = 0; j < n_points; j++) {
      if (points != null) {
        if (points_idx + j < points.length) {
          if (getPoint(j) != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" outl: %d %5d %5d", j, getPoint(j).x, getPoint(j).y));
          }
        }
      }
      if (extra_points != null) {
        if (j < extra_points.length) {
          if (getExtra_point(j) != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" ext1: %d %5d %5d", j, getExtra_point(j).x, getExtra_point(j).y));
          }
        }
      }
      if (extra_points2 != null) {
        if (extra_points2_idx + j < extra_points2.length) {
          if (getExtra_point2(j) != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" ext2: %d %5d %5d", j, getExtra_point2(j).x, getExtra_point2(j).y));
          }
        }
      }
    }
  }

  /* ==================== getExtra_point ===================================== */







|






|






|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "loaderLoad.extra_points2: "+extra_points2+"!"+extra_points2_idx);
    }
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "Show loaderLoad");
    for (j = 0; j < n_points; j++) {
      if (points != null) {
        if (points_idx + j < points.length) {
          if (getPoint(j) != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" outl: %d %5d %5d", j, getPoint(j).getX(), getPoint(j).getY()));
          }
        }
      }
      if (extra_points != null) {
        if (j < extra_points.length) {
          if (getExtra_point(j) != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" ext1: %d %5d %5d", j, getExtra_point(j).getX(), getExtra_point(j).getY()));
          }
        }
      }
      if (extra_points2 != null) {
        if (extra_points2_idx + j < extra_points2.length) {
          if (getExtra_point2(j) != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" ext2: %d %5d %5d", j, getExtra_point2(j).getX(), getExtra_point2(j).getY()));
          }
        }
      }
    }
  }

  /* ==================== getExtra_point ===================================== */

Changes to aftbase/FTGlyphLoaderRec.java.

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    /* create FT_Glyph object */
    glyph = new FTGlyphRec();
    glyph.initGlyph(library, clazz);
    if (error != FTError.ErrorTag.ERR_OK) {
      return error;
    }
    /* copy advance while converting it to 16.16 format */
    glyph.advance.x = slot.getAdvance().x << 10;
    glyph.advance.y = slot.getAdvance().y << 10;
    /* now import the image from the glyph slot */
    error = clazz.glyphInit(glyph, slot);
    /* if an error occurred, destroy the glyph */
    if (error != FTError.ErrorTag.ERR_OK) {
      FTDoneGlyph(glyph);
    } else {
      glyph_ref.Set(glyph);
................................................................................
  }

  /* =====================================================================
   * translate_array
   *
   * =====================================================================
   */
  public static void translate_array(int n, FTVectorRec[] coords, int idx, long delta_x, long delta_y) {
    int k;

    if (delta_x != 0) {
      for (k = 0; k < n; k++) {
        coords[idx + k].x += delta_x;
      }
    }
    if (delta_y != 0) {
      for (k = 0; k < n; k++) {
        coords[idx + k].y += delta_y;
      }
    }
  }

  /* =====================================================================
   * GlyphLoaderAdjustPoints
   *
................................................................................
        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].x = base.getExtra_points()[old_max + k].x;
            base.getExtra_points()[new_max + k].y = base.getExtra_points()[old_max + k].y;
          }
          base.setExtra_points2(new FTVectorRec[new_max]);
          for (k = old_max; k < old_max * 2; k++) {
            base.getExtra_points2()[k - old_max] = base.getExtra_point(k);
          }
          for (k = old_max; k < new_max; k++) {
            base.getExtra_points2()[k] = new FTVectorRec();







|
|







 







|




|




|







 







|
|







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
    /* create FT_Glyph object */
    glyph = new FTGlyphRec();
    glyph.initGlyph(library, clazz);
    if (error != FTError.ErrorTag.ERR_OK) {
      return error;
    }
    /* copy advance while converting it to 16.16 format */
    glyph.advance.setX(slot.getAdvance().getX() << 10);
    glyph.advance.setY(slot.getAdvance().getY() << 10);
    /* now import the image from the glyph slot */
    error = clazz.glyphInit(glyph, slot);
    /* if an error occurred, destroy the glyph */
    if (error != FTError.ErrorTag.ERR_OK) {
      FTDoneGlyph(glyph);
    } else {
      glyph_ref.Set(glyph);
................................................................................
  }

  /* =====================================================================
   * translate_array
   *
   * =====================================================================
   */
  public static void translate_array(int n, FTVectorRec[] coords, int idx, int delta_x, int delta_y) {
    int k;

    if (delta_x != 0) {
      for (k = 0; k < n; k++) {
        coords[idx + k].setX(coords[idx + k].getX() + delta_x);
      }
    }
    if (delta_y != 0) {
      for (k = 0; k < n; k++) {
        coords[idx + k].setY(coords[idx + k].getY() + delta_y);
      }
    }
  }

  /* =====================================================================
   * GlyphLoaderAdjustPoints
   *
................................................................................
        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());
            base.getExtra_points()[new_max + k].setY(base.getExtra_points()[old_max + k].getY());
          }
          base.setExtra_points2(new FTVectorRec[new_max]);
          for (k = old_max; k < old_max * 2; k++) {
            base.getExtra_points2()[k - old_max] = base.getExtra_point(k);
          }
          for (k = old_max; k < new_max; k++) {
            base.getExtra_points2()[k] = new FTVectorRec();

Changes to aftbase/FTGlyphSlotRec.java.

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
...
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
  }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("..linearHoriAdvance: "+linearHoriAdvance+'\n');
    str.append("..linearVertAdvance: "+linearVertAdvance+'\n');
    str.append("..advance: "+advance.x+" "+advance.y+'\n');
    str.append("..format: "+format+'\n');
    str.append("..bitmap_left: "+bitmap_left+'\n');
    str.append("..bitmap_top: "+bitmap_top+'\n');
    str.append("..num_subglyphs: "+num_subglyphs+'\n');
    str.append("..control_len: "+control_len+'\n');
    str.append("..lsb_delta: "+lsb_delta+'\n');
    str.append("..rsb_delta: "+rsb_delta+'\n');
................................................................................
    if (hinter != null &&
        ((load_flags & Flags.Load.NO_HINTING.getVal()) == 0) &&
        ((load_flags & Flags.Load.NO_AUTOHINT.getVal()) == 0) &&
        ((driver.getDriver_clazz().module_flags & Flags.Module.DRIVER_SCALABLE.getVal()) != 0) &&
        ((driver.getDriver_clazz().module_flags & Flags.Module.DRIVER_NO_OUTLINES.getVal()) == 0) &&
        ((face.getFace_flags() & Flags.Face.TRICKY.getVal()) == 0) &&
        (((load_flags & Flags.Load.IGNORE_TRANSFORM.getVal()) != 0) ||
            (face.getInternal().getTransform_matrix().yx == 0 && face.getInternal().getTransform_matrix().xx != 0) ||
            (face.getInternal().getTransform_matrix().xx == 0 && face.getInternal().getTransform_matrix().yx != 0))) {
      if (((load_flags & Flags.Load.FORCE_AUTOHINT.getVal()) != 0) ||
          ((driver.getDriver_clazz().module_flags & Flags.Module.DRIVER_HAS_HINTER.getVal()) == 0)) {
        autohint = true;
      } else {
        int mode = ((load_flags >> 16 ) & 15);
        /* the check for `num_locations' assures that we actually    */
        /* test for instructions in a TTF and not in a CFF-based OTF */
................................................................................
        if (error != FTError.ErrorTag.ERR_OK) {
          return error;
        }
      }
    }
    /* compute the advance */
    if ((load_flags & Flags.Load.VERTICAL_LAYOUT.getVal()) != 0) {
      advance.x = 0;
      advance.y = metrics.getVertAdvance();
    } else {
      advance.x = metrics.getHoriAdvance();
      advance.y = 0;
    }
    /* compute the linear advance in 16.16 pixels */
    if (((load_flags & Flags.Load.LINEAR_DESIGN.getVal()) == 0) && ((face.getFace_flags() & Flags.Face.SCALABLE.getVal()) != 0)) {
      FTSizeMetricsRec metrics = face.getSize().metrics;

      /* it's tricky! */
      linearHoriAdvance = FTCalc.FT_MulDiv(linearHoriAdvance, metrics.getX_scale(), 64);
................................................................................
          if (format == FTTags.GlyphFormat.OUTLINE) {
            /* apply `standard' transformation if no renderer is available */
            if ((internal.getTransform_flags() & 1) != 0) {
              Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "standard outline transform");
              outline.OutlineTransform(internal.getTransform_matrix());
            }
            if ((internal.getTransform_flags() & 2) != 0) {
              outline.OutlineTranslate(internal.getTransform_delta().x, internal.getTransform_delta().y);
            }
          }
        }
        /* transform advance */
        outline.VectorTransform(advance, internal.getTransform_matrix());
        internal.setTransform_matrix(matrix_ref.Get());
      }
    }
    FTTrace.Trace(7, TAG, String.format("  x advance: %d", advance.x));
    FTTrace.Trace(7, TAG, String.format("  y advance: %d", advance.y));
    FTTrace.Trace(7, TAG, String.format("  linear x advance: %d", linearHoriAdvance));
    FTTrace.Trace(7, TAG, String.format("  linear y advance: %d", linearVertAdvance));
    /* do we need to render the image now? */
    if (error == FTError.ErrorTag.ERR_OK &&
        (format != FTTags.GlyphFormat.BITMAP) &&
        (format != FTTags.GlyphFormat.COMPOSITE) &&
        (load_flags & Flags.Load.RENDER.getVal()) != 0) {







|







 







|
|







 







|
|

|
|







 







|








|
|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
...
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
...
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
  }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("..linearHoriAdvance: "+linearHoriAdvance+'\n');
    str.append("..linearVertAdvance: "+linearVertAdvance+'\n');
    str.append("..advance: "+advance.getX()+" "+advance.getY()+'\n');
    str.append("..format: "+format+'\n');
    str.append("..bitmap_left: "+bitmap_left+'\n');
    str.append("..bitmap_top: "+bitmap_top+'\n');
    str.append("..num_subglyphs: "+num_subglyphs+'\n');
    str.append("..control_len: "+control_len+'\n');
    str.append("..lsb_delta: "+lsb_delta+'\n');
    str.append("..rsb_delta: "+rsb_delta+'\n');
................................................................................
    if (hinter != null &&
        ((load_flags & Flags.Load.NO_HINTING.getVal()) == 0) &&
        ((load_flags & Flags.Load.NO_AUTOHINT.getVal()) == 0) &&
        ((driver.getDriver_clazz().module_flags & Flags.Module.DRIVER_SCALABLE.getVal()) != 0) &&
        ((driver.getDriver_clazz().module_flags & Flags.Module.DRIVER_NO_OUTLINES.getVal()) == 0) &&
        ((face.getFace_flags() & Flags.Face.TRICKY.getVal()) == 0) &&
        (((load_flags & Flags.Load.IGNORE_TRANSFORM.getVal()) != 0) ||
            (face.getInternal().getTransform_matrix().getYx() == 0 && face.getInternal().getTransform_matrix().getXx() != 0) ||
            (face.getInternal().getTransform_matrix().getXx() == 0 && face.getInternal().getTransform_matrix().getYx() != 0))) {
      if (((load_flags & Flags.Load.FORCE_AUTOHINT.getVal()) != 0) ||
          ((driver.getDriver_clazz().module_flags & Flags.Module.DRIVER_HAS_HINTER.getVal()) == 0)) {
        autohint = true;
      } else {
        int mode = ((load_flags >> 16 ) & 15);
        /* the check for `num_locations' assures that we actually    */
        /* test for instructions in a TTF and not in a CFF-based OTF */
................................................................................
        if (error != FTError.ErrorTag.ERR_OK) {
          return error;
        }
      }
    }
    /* compute the advance */
    if ((load_flags & Flags.Load.VERTICAL_LAYOUT.getVal()) != 0) {
      advance.setX(0);
      advance.setY(metrics.getVertAdvance());
    } else {
      advance.setX(metrics.getHoriAdvance());
      advance.setY(0);
    }
    /* compute the linear advance in 16.16 pixels */
    if (((load_flags & Flags.Load.LINEAR_DESIGN.getVal()) == 0) && ((face.getFace_flags() & Flags.Face.SCALABLE.getVal()) != 0)) {
      FTSizeMetricsRec metrics = face.getSize().metrics;

      /* it's tricky! */
      linearHoriAdvance = FTCalc.FT_MulDiv(linearHoriAdvance, metrics.getX_scale(), 64);
................................................................................
          if (format == FTTags.GlyphFormat.OUTLINE) {
            /* apply `standard' transformation if no renderer is available */
            if ((internal.getTransform_flags() & 1) != 0) {
              Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "standard outline transform");
              outline.OutlineTransform(internal.getTransform_matrix());
            }
            if ((internal.getTransform_flags() & 2) != 0) {
              outline.OutlineTranslate(internal.getTransform_delta().getX(), internal.getTransform_delta().getY());
            }
          }
        }
        /* transform advance */
        outline.VectorTransform(advance, internal.getTransform_matrix());
        internal.setTransform_matrix(matrix_ref.Get());
      }
    }
    FTTrace.Trace(7, TAG, String.format("  x advance: %d", advance.getX()));
    FTTrace.Trace(7, TAG, String.format("  y advance: %d", advance.getY()));
    FTTrace.Trace(7, TAG, String.format("  linear x advance: %d", linearHoriAdvance));
    FTTrace.Trace(7, TAG, String.format("  linear y advance: %d", linearVertAdvance));
    /* do we need to render the image now? */
    if (error == FTError.ErrorTag.ERR_OK &&
        (format != FTTags.GlyphFormat.BITMAP) &&
        (format != FTTags.GlyphFormat.COMPOSITE) &&
        (load_flags & Flags.Load.RENDER.getVal()) != 0) {

Changes to aftbase/FTOutlineRec.java.

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
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
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
   * =====================================================================
   */
  public void OutlineTranslate(int xOffset, int yOffset) {
    int n;

Debug(0, DebugTag.DBG_RENDER, TAG, "FTOutlineTranslate");
    for (n = 0; n < n_points; n++) {
      points[n].x += xOffset;
      points[n].y += yOffset;
    }
  }

  /* =====================================================================
   * OutlineTransform
   * =====================================================================
   */
................................................................................
  public void VectorTransform(FTVectorRec vec, FTMatrixRec matrix) {
    int xz;
    int yz;

    if (vec == null || matrix == null) {
      return;
    }
    xz = FTCalc.FTMulFix(vec.x, matrix.xx) + FTCalc.FTMulFix(vec.y, matrix.xy);
    yz = FTCalc.FTMulFix(vec.x, matrix.yx) + FTCalc.FTMulFix(vec.y, matrix.yy);
    vec.x = xz;
    vec.y = yz;
  }
    
  /* =====================================================================
   * FTOutlineGetCBox
   * =====================================================================
   */
  public void FTOutlineGetCBox(FTReference<FTBBoxRec> cbox_ref) {
................................................................................
      } else {
        int vecIdx = 0;
        int limit = n_points;
        FTVectorRec vec;

int i;
for (i = 0; i < n_points; i++) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("FTOutLineGetCBox: i: %d x: %d y: %d\n", i, points[i].x, points[i].y));
}
        vec = points[vecIdx];
        xMin = xMax = vec.x;
        yMin = yMax = vec.y;
        vecIdx++;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("xMin: xMin: %d xMax: %d yMin: %d yMax: %d vecIdx: %d", xMin, xMax, yMin, yMax, vecIdx));

        for ( ; vecIdx < limit; vecIdx++) {
          int x;
          int y;

          vec = points[vecIdx];
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("vec: %d %d %d", vecIdx, vec.x, vec.y));
          x = vec.x;
          if (x < xMin) {
            xMin = x;
          }
          if (x > xMax) {
            xMax = x;
          }
          y = vec.y;
          if (y < yMin) {
            yMin = y;
          }
          if (y > yMax) {
            yMax = y;
          }
        }
................................................................................
      FTTrace.Trace(7, TAG, String.format("ftoutline FT_Outline_Decompose: Outline %d of %d", n, n_contours));
      last = contours[n];
      if (last < 0) {
        return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
      }
      limit = last;
      v_start = points[first];
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("first: %d,  last: %d, v_start.x: %d, v_start.y: %d", first, last, v_start.x, v_start.y));
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("delta: %d, shift: %d", delta, shift));
      v_start.x = (((v_start.x) << shift) - delta);
      v_start.y = (((v_start.y) << shift) - delta);
      v_last = points[last];
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("v_last.x: %d, v_last.y: %d", v_last.x, v_last.y));
      v_last.x = (((v_last.x) << shift) - delta);
      v_last.y = (((v_last.y) << shift) - delta);
      v_control.x = v_start.x;
      v_control.y = v_start.y;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("v_start: %d %d v_last: %d %d", v_start.x, v_start.y, v_last.x, v_last.y));
      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.x = v_last.x;
          v_start.y = v_last.y;
          limit--;
        } else {
          /* if both first and last points are conic,         */
          /* start at their middle and record its position    */
          /* for closure                                      */
          v_start.x = (v_start.x + v_last.x) / 2;
          v_start.y = (v_start.y + v_last.y) / 2;
          v_last.x = v_start.x;
          v_last.y = v_start.y;
        }
        pointIdx--;
        tagsIdx--;
      }
Debug(0, DebugTag.DBG_RENDER, TAG, "Decompose:");
      FTTrace.Trace(7, TAG, String.format("  move to (%.2f, %.2f)",
                  v_start.x / 64.0, v_start.y / 64.0));
      error = func_interface.moveTo(v_start, user);
      FTTrace.Trace(7, TAG, String.format("  move to after (%.2f, %.2f)",
          v_start.x / 64.0, v_start.y / 64.0));
      if (error != FTError.ErrorTag.ERR_OK) {
        FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
        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.x, v_start.y));
        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.x = (((points[pointIdx].x) << shift) - delta);
            vec.y = (((points[pointIdx].y) << shift) - delta);
            FTTrace.Trace(7, TAG, String.format("  line to (%.2f, %.2f)\n",
                        vec.x / 64.0, vec.y / 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.x, v_start.y));
          v_control.x = (((points[pointIdx].x) << shift) - delta);
          v_control.y = (((points[pointIdx].y) << 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.x, v_start.y));
            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.x = (((points[pointIdx].x) << shift) - delta);
              vec.y = (((points[pointIdx].y) << 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.x, vec.y));
              if (tag == Flags.Curve.ON) {
                FTTrace.Trace(0, TAG, String.format("  1 conic to (%.2f, %.2f)"+
                          " with control (%.2f, %.2f)",
                          vec.x / 64.0, vec.y / 64.0,
                          v_control.x / 64.0, v_control.y / 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.x = ( v_control.x + vec.x ) / 2;
              v_middle.y = ( v_control.y + vec.y ) / 2;
              FTTrace.Trace(7, TAG, String.format("  2 conic to (%.2f, %.2f)"+
                        " with control (%.2f, %.2f)",
                        v_middle.x / 64.0, v_middle.y / 64.0,
                        v_control.x / 64.0, v_control.y / 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.x = vec.x;
              v_control.y = vec.y;
              doConic = true;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==4a v_start.x: %d, v_start.y: %d", v_start.x, v_start.y));
            }
          }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==4b v_start.x: %d, v_start.y: %d", v_start.x, v_start.y));
          if (doContinue) {
            continue;
          }
          FTTrace.Trace(8, TAG, String.format(" 3 conic to (%.2f, %.2f)"+
                      " with control (%.2f, %.2f)",
                      v_start.x / 64.0, v_start.y / 64.0,
                      v_control.x / 64.0, v_control.y / 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;
................................................................................
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.x = (((points[pointIdx - 2].x) << shift) - delta);;
            vec1.y = (((points[pointIdx - 2].y) << shift) - delta);;
            vec2.x = (((points[pointIdx - 1].x) << shift) - delta);;
            vec2.y = (((points[pointIdx - 1].y) << shift) - delta);;
            if (pointIdx <= limit) {
              FTVectorRec vec = new FTVectorRec();

              vec.x = (((points[pointIdx].x) << shift) - delta);;
              vec.y = (((points[pointIdx].y) << shift) - delta);
              FTTrace.Trace(7, TAG, String.format(" 1 cubic to (%.2f, %.2f)"+
                          " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
                          vec.x / 64.0, vec.y / 64.0,
                          vec1.x / 64.0, vec1.y / 64.0,
                          vec2.x / 64.0, vec2.y / 64.0));
              error = func_interface.cubicTo(vec1, vec2, vec, user);
              if (error != FTError.ErrorTag.ERR_OK) {
                FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
                return error;
              }
              continue;
            }
            FTTrace.Trace(7, TAG, String.format(" 2 cubic to (%.2f, %.2f)"+
                        " with controls (%.2f, %.2f) and (%.2f, %.2f)",
                        v_start.x / 64.0, v_start.y / 64.0,
                        vec1.x / 64.0, vec1.y / 64.0,
                        vec2.x / 64.0, vec2.y / 64.0));
            error = func_interface.cubicTo(vec1, vec2, 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;
          }
        }
      }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==5 v_start.x: %d, v_start.y: %d", v_start.x, v_start.y));
      if (! isClosed) {
        /* close the contour with a line segment */
        FTTrace.Trace(7, TAG, String.format(" 2 line to (%.2f, %.2f)",
                  v_start.x / 64.0, v_start.y / 64.0));
        error = func_interface.lineTo(v_start, user);
      }
      if (error != FTError.ErrorTag.ERR_OK) {
        FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
        return error;
      }
      first = last + 1;







|
|







 







|
|
|
|







 







|


|
|








|
|






|







 







|

|
|

|
|
|
|
|
|












|
|





|
|
|
|






|


|






|










|
|

|









|
|
|




|








|
|
|



|
|












|
|


|
|






|
|

|


|





|
|







 







|
|
|
|



|
|


|
|
|









|
|
|










|



|







188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
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
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
   * =====================================================================
   */
  public void OutlineTranslate(int xOffset, int yOffset) {
    int n;

Debug(0, DebugTag.DBG_RENDER, TAG, "FTOutlineTranslate");
    for (n = 0; n < n_points; n++) {
      points[n].setX(points[n].getX() + xOffset);
      points[n].setY(points[n].getY() + yOffset);
    }
  }

  /* =====================================================================
   * OutlineTransform
   * =====================================================================
   */
................................................................................
  public void VectorTransform(FTVectorRec vec, FTMatrixRec matrix) {
    int xz;
    int yz;

    if (vec == null || matrix == null) {
      return;
    }
    xz = FTCalc.FTMulFix(vec.getX(), matrix.getXx()) + FTCalc.FTMulFix(vec.getY(), matrix.getXy());
    yz = FTCalc.FTMulFix(vec.getY(), matrix.getYx()) + FTCalc.FTMulFix(vec.getY(), matrix.getYy());
    vec.setX(xz);
    vec.setY(yz);
  }
    
  /* =====================================================================
   * FTOutlineGetCBox
   * =====================================================================
   */
  public void FTOutlineGetCBox(FTReference<FTBBoxRec> cbox_ref) {
................................................................................
      } else {
        int vecIdx = 0;
        int limit = n_points;
        FTVectorRec vec;

int i;
for (i = 0; i < n_points; i++) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("FTOutLineGetCBox: i: %d x: %d y: %d\n", i, points[i].getX(), points[i].getY()));
}
        vec = points[vecIdx];
        xMin = xMax = vec.getX();
        yMin = yMax = vec.getY();
        vecIdx++;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("xMin: xMin: %d xMax: %d yMin: %d yMax: %d vecIdx: %d", xMin, xMax, yMin, yMax, vecIdx));

        for ( ; vecIdx < limit; vecIdx++) {
          int x;
          int y;

          vec = points[vecIdx];
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("vec: %d %d %d", vecIdx, vec.getX(), vec.getY()));
          x = vec.getX();
          if (x < xMin) {
            xMin = x;
          }
          if (x > xMax) {
            xMax = x;
          }
          y = vec.getY();
          if (y < yMin) {
            yMin = y;
          }
          if (y > yMax) {
            yMax = y;
          }
        }
................................................................................
      FTTrace.Trace(7, TAG, String.format("ftoutline FT_Outline_Decompose: Outline %d of %d", n, n_contours));
      last = contours[n];
      if (last < 0) {
        return FTError.ErrorTag.RENDER_INVALID_OUTLINE;
      }
      limit = last;
      v_start = points[first];
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("first: %d,  last: %d, v_start.x: %d, v_start.y: %d", first, last, v_start.getX(), v_start.getY()));
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("delta: %d, shift: %d", delta, shift));
      v_start.setX(((v_start.getX()) << shift) - delta);
      v_start.setY(((v_start.getY()) << shift) - delta);
      v_last = points[last];
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("v_last.x: %d, v_last.y: %d", v_last.getX(), v_last.getY()));
      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    */
          /* for closure                                      */
          v_start.setX((v_start.getX() + v_last.getX()) / 2);
          v_start.setY((v_start.getY() + v_last.getY()) / 2);
          v_last.setX(v_start.getX());
          v_last.setY(v_start.getY());
        }
        pointIdx--;
        tagsIdx--;
      }
Debug(0, DebugTag.DBG_RENDER, TAG, "Decompose:");
      FTTrace.Trace(7, TAG, String.format("  move to (%.2f, %.2f)",
                  v_start.getX() / 64.0, v_start.getY() / 64.0));
      error = func_interface.moveTo(v_start, user);
      FTTrace.Trace(7, TAG, String.format("  move to after (%.2f, %.2f)",
          v_start.getX() / 64.0, v_start.getY() / 64.0));
      if (error != FTError.ErrorTag.ERR_OK) {
        FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
        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;
................................................................................
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));
            vec2.setY((((points[pointIdx - 1].getY()) << shift) - delta));
            if (pointIdx <= limit) {
              FTVectorRec vec = new FTVectorRec();

              vec.setX((((points[pointIdx].getX()) << shift) - delta));
              vec.setY((((points[pointIdx].getY()) << shift) - delta));
              FTTrace.Trace(7, TAG, String.format(" 1 cubic to (%.2f, %.2f)"+
                          " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
                          vec.getX() / 64.0, vec.getY() / 64.0,
                          vec1.getX() / 64.0, vec1.getY() / 64.0,
                          vec2.getX() / 64.0, vec2.getY() / 64.0));
              error = func_interface.cubicTo(vec1, vec2, vec, user);
              if (error != FTError.ErrorTag.ERR_OK) {
                FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
                return error;
              }
              continue;
            }
            FTTrace.Trace(7, TAG, String.format(" 2 cubic to (%.2f, %.2f)"+
                        " with controls (%.2f, %.2f) and (%.2f, %.2f)",
                        v_start.getX() / 64.0, v_start.getY() / 64.0,
                        vec1.getX() / 64.0, vec1.getY() / 64.0,
                        vec2.getX() / 64.0, vec2.getY() / 64.0));
            error = func_interface.cubicTo(vec1, vec2, 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;
          }
        }
      }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("==5 v_start.x: %d, v_start.y: %d", v_start.getX(), v_start.getY()));
      if (! isClosed) {
        /* close the contour with a line segment */
        FTTrace.Trace(7, TAG, String.format(" 2 line to (%.2f, %.2f)",
                  v_start.getX() / 64.0, v_start.getY() / 64.0));
        error = func_interface.lineTo(v_start, user);
      }
      if (error != FTError.ErrorTag.ERR_OK) {
        FTTrace.Trace(7, TAG, String.format("FT_Outline_Decompose: Error %d", error));
        return error;
      }
      first = last + 1;

Changes to aftbase/FTRendererClassRec.java.

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import android.util.Log;

import org.apwtcl.apwfreetypelib.aftraster.FTRasterParamsRec;
import org.apwtcl.apwfreetypelib.aftraster.FTRasterRec;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTMatrixRec;
import org.apwtcl.apwfreetypelib.aftutil.FTParameter;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

public class FTRendererClassRec extends FTModuleClassRec {
  private static int oid = 0;

  private int id;
................................................................................
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Log.e(TAG, "getGlyphCBox not yet implemented");
    return error;
  }

  /* ==================== setMode ===================================== */
  public FTError.ErrorTag setMode(FTRendererRec renderer, FTParameter.ParamTag tag, Object data) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Log.e(TAG, "SetMode not yet implemented");
    return error;
  }

  /* ==================== getGlyphFormat ===================================== */







|







 







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import android.util.Log;

import org.apwtcl.apwfreetypelib.aftraster.FTRasterParamsRec;
import org.apwtcl.apwfreetypelib.aftraster.FTRasterRec;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTMatrixRec;
import org.apwtcl.apwfreetypelib.aftutil.FTParameterRec;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

public class FTRendererClassRec extends FTModuleClassRec {
  private static int oid = 0;

  private int id;
................................................................................
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Log.e(TAG, "getGlyphCBox not yet implemented");
    return error;
  }

  /* ==================== setMode ===================================== */
  public FTError.ErrorTag setMode(FTRendererRec renderer, FTParameterRec.ParamTag tag, Object data) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Log.e(TAG, "SetMode not yet implemented");
    return error;
  }

  /* ==================== getGlyphFormat ===================================== */

Changes to aftbase/FTRendererRec.java.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftraster.FTRasterParamsRec;
import org.apwtcl.apwfreetypelib.aftraster.FTRasterRec;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTParameter;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

public class FTRendererRec extends FTModuleRec {
  private static int oid = 0;

  private int id;
................................................................................
    return result;
  }

  /* =====================================================================
   * FTSetRenderer
   * =====================================================================
   */
  public static FTError.ErrorTag FTSetRenderer(FTLibraryRec library, FTRendererRec renderer, int num_params, FTParameter[] parameters) {
FTDebug.Debug(0, FTDebug.DebugTag.DBG_RENDER, TAG, "FTSetRenderer");
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTListNodeRec node;
    FTParameter parameter;
    int parameterIdx = 0;

    if (library == null) {
      return FTError.ErrorTag.RENDER_INVALID_LIBRARY_HANDLE;
    }
    if (renderer == null) {
      return FTError.ErrorTag.RENDER_INVALID_ARGUMENT;







|







 







|



|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftraster.FTRasterParamsRec;
import org.apwtcl.apwfreetypelib.aftraster.FTRasterRec;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTParameterRec;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

public class FTRendererRec extends FTModuleRec {
  private static int oid = 0;

  private int id;
................................................................................
    return result;
  }

  /* =====================================================================
   * FTSetRenderer
   * =====================================================================
   */
  public static FTError.ErrorTag FTSetRenderer(FTLibraryRec library, FTRendererRec renderer, int num_params, FTParameterRec[] parameters) {
FTDebug.Debug(0, FTDebug.DebugTag.DBG_RENDER, TAG, "FTSetRenderer");
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTListNodeRec node;
    FTParameterRec parameter;
    int parameterIdx = 0;

    if (library == null) {
      return FTError.ErrorTag.RENDER_INVALID_LIBRARY_HANDLE;
    }
    if (renderer == null) {
      return FTError.ErrorTag.RENDER_INVALID_ARGUMENT;

Changes to aftbase/FTStrokerRec.java.

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      str.append("..angle_in: "+angle_in+'\n');
      str.append("..angle_out: "+angle_out+'\n');
      str.append("..center: "+center.x+" "+center.y+'\n');
      str.append("..line_length: "+line_length+'\n');
      str.append("..first_point: "+first_point+'\n');
      str.append("..subpath_open: "+subpath_open+'\n');
      str.append("..subpath_angle: "+subpath_angle+'\n');
      str.append("..subpath_start: "+subpath_start.x+" "+subpath_start.y+'\n');
      str.append("..subpath_line_length: "+subpath_line_length+'\n');
      str.append("..handle_wide_strokes: "+handle_wide_strokes+'\n');
      str.append("..line_cap: "+line_cap+'\n');
      str.append("..line_join: "+line_join+'\n');
      str.append("..line_join_saved: "+line_join_saved+'\n');
      str.append("..miter_limit: "+miter_limit+'\n');
      str.append("..radius: "+radius+'\n');







|




|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      str.append("..angle_in: "+angle_in+'\n');
      str.append("..angle_out: "+angle_out+'\n');
      str.append("..center: "+center.getX()+" "+center.getY()+'\n');
      str.append("..line_length: "+line_length+'\n');
      str.append("..first_point: "+first_point+'\n');
      str.append("..subpath_open: "+subpath_open+'\n');
      str.append("..subpath_angle: "+subpath_angle+'\n');
      str.append("..subpath_start: "+subpath_start.getX()+" "+subpath_start.getY()+'\n');
      str.append("..subpath_line_length: "+subpath_line_length+'\n');
      str.append("..handle_wide_strokes: "+handle_wide_strokes+'\n');
      str.append("..line_cap: "+line_cap+'\n');
      str.append("..line_join: "+line_join+'\n');
      str.append("..line_join_saved: "+line_join_saved+'\n');
      str.append("..miter_limit: "+miter_limit+'\n');
      str.append("..radius: "+radius+'\n');

Changes to aftdemo/demo1.java.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import android.os.Environment;
import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.FTApwFreeType;
import org.apwtcl.apwfreetypelib.aftbase.FTBitmapRec;
import org.apwtcl.apwfreetypelib.aftbase.FTFaceRec;
import org.apwtcl.apwfreetypelib.aftbase.FTFaceRequester;
import org.apwtcl.apwfreetypelib.aftbase.FTGlyphLoaderRec;
import org.apwtcl.apwfreetypelib.aftbase.FTLibraryRec;
import org.apwtcl.apwfreetypelib.aftbase.FTSizeRec;
import org.apwtcl.apwfreetypelib.aftbase.FTStrokerRec;
import org.apwtcl.apwfreetypelib.aftcache.FTCBasicICacheClass;
import org.apwtcl.apwfreetypelib.aftcache.FTCBasicSCacheClass;
import org.apwtcl.apwfreetypelib.aftcache.FTCCMapCacheClass;
import org.apwtcl.apwfreetypelib.aftcache.FTCGCacheClassRec;
import org.apwtcl.apwfreetypelib.aftcache.FTCManagerRec;
import org.apwtcl.apwfreetypelib.aftcache.FTCScalerRec;
import org.apwtcl.apwfreetypelib.aftdemo.FTDemoFaceRequester;
import org.apwtcl.apwfreetypelib.aftdemo.TFont;
import org.apwtcl.apwfreetypelib.afttruetype.TTFaceRec;
import org.apwtcl.apwfreetypelib.aftutil.*;

import java.io.IOException;

public class demo1 extends FTDebug {

  public static String TAG = "cl1";

  public demo1() {
    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    System.out.println("path:" + path + "!");
    String font_file_name = path + "/Vera.ttf";
    int face_index = 0;
    int max_faces = 0;
    int max_sizes = 0;

    try {
      FTOpenArgs open_args = new FTOpenArgs();
      open_args.setPathname(font_file_name);

      TFont font_args = new TFont();
      font_args.setFilepathname(font_file_name);
      font_args.setFace_index(face_index);

      FTApwFreeType freetype = new FTApwFreeType();







<









<
<
<


<
<













|







7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22



23
24


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import android.os.Environment;
import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.FTApwFreeType;
import org.apwtcl.apwfreetypelib.aftbase.FTBitmapRec;
import org.apwtcl.apwfreetypelib.aftbase.FTFaceRec;
import org.apwtcl.apwfreetypelib.aftbase.FTFaceRequester;

import org.apwtcl.apwfreetypelib.aftbase.FTLibraryRec;
import org.apwtcl.apwfreetypelib.aftbase.FTSizeRec;
import org.apwtcl.apwfreetypelib.aftbase.FTStrokerRec;
import org.apwtcl.apwfreetypelib.aftcache.FTCBasicICacheClass;
import org.apwtcl.apwfreetypelib.aftcache.FTCBasicSCacheClass;
import org.apwtcl.apwfreetypelib.aftcache.FTCCMapCacheClass;
import org.apwtcl.apwfreetypelib.aftcache.FTCGCacheClassRec;
import org.apwtcl.apwfreetypelib.aftcache.FTCManagerRec;
import org.apwtcl.apwfreetypelib.aftcache.FTCScalerRec;



import org.apwtcl.apwfreetypelib.aftutil.*;



public class demo1 extends FTDebug {

  public static String TAG = "cl1";

  public demo1() {
    String path = Environment.getExternalStorageDirectory().getAbsolutePath();
    System.out.println("path:" + path + "!");
    String font_file_name = path + "/Vera.ttf";
    int face_index = 0;
    int max_faces = 0;
    int max_sizes = 0;

    try {
      FTOpenArgsRec open_args = new FTOpenArgsRec();
      open_args.setPathname(font_file_name);

      TFont font_args = new TFont();
      font_args.setFilepathname(font_file_name);
      font_args.setFace_index(face_index);

      FTApwFreeType freetype = new FTApwFreeType();

Changes to aftraster/FTGrayOutlineFuncsClass.java.

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
98
99
100
101
102
...
546
547
548
549
550
551
552
553
554

555

556
557
558
559

560

561
562
563
564
565
566
567
568
569
...
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
...
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
...
663
664
665
666
667
668
669
670
671
672
673

674

675
676

677
678
679

680
681
682

683

684
685

686

687
688
689
690
691
692
693
694
...
700
701
702
703
704
705
706
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
737
738
739
740
741
742
743
744
745
746
747
...
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
...
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
...
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
   *
   * =====================================================================
   */
  private FTError.ErrorTag gray_move_to(FTVectorRec to, grayTWorkerRec worker) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    int x;
    int y;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_move_to: to.x: %d, to.y: %d", to.x, to.y));

      /* record current cell, if any */
    gray_record_cell(worker);
      /* start to a new position */
    x = RasterUtil.UPSCALE(to.x);
    y = RasterUtil.UPSCALE(to.y);
    gray_start_cell(worker, RasterUtil.TRUNC(x), RasterUtil.TRUNC(y));
    worker.setX(x);
    worker.setY(y);
    return error;
  }

  /* =====================================================================
   *    gray_line_to
   *
   * =====================================================================
   */
  private FTError.ErrorTag gray_line_to(FTVectorRec to, grayTWorkerRec worker) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_line_to: to.x: %d, to.y: %d", to.x, to.y));
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Debug(0, DebugTag.DBG_RENDER, TAG, "gray_line_to call gray_render_line");
    gray_render_line(worker, RasterUtil.UPSCALE(to.x), RasterUtil.UPSCALE(to.y));
    Debug(0, DebugTag.DBG_RENDER, TAG, "gray_line_to after call gray_render_line");
    return error;
  }

  /* =====================================================================
   *    gray_conic_to
   *
................................................................................
   */
  private void gray_split_conic(FTReference<FTVectorRec[]> base_ref, int arcIdx) {
Debug(0, DebugTag.DBG_RENDER, TAG, "gray_split_conic");
    FTVectorRec[] base = base_ref.Get();
    int a;
    int b;

    base[arcIdx + 4].x = base[arcIdx + 2].x;
    b = base[arcIdx + 1].x;

    a = base[arcIdx + 3].x = (base[arcIdx + 2].x + b) / 2;

    b = base[arcIdx + 1].x = (base[arcIdx + 0].x + b) / 2;
    base[arcIdx + 2].x = (a + b) / 2;
    base[arcIdx + 4].y = base[arcIdx + 2].y;
    b = base[arcIdx + 1].y;

    a = base[arcIdx + 3].y = (base[arcIdx + 2].y + b) / 2;

    b = base[arcIdx + 1].y = (base[arcIdx + 0].y + b) / 2;
    base[arcIdx + 2].y = (a + b) / 2;
    base_ref.Set(base);
  }

  /* =====================================================================
   *    gray_render_conic
   *
   * =====================================================================
................................................................................
    FTReference<FTVectorRec[]> arc_ref = new FTReference<FTVectorRec[]>();
    int arcIdx = 0;
    boolean doDraw = false;

Debug(0, DebugTag.DBG_RENDER, TAG, "gray_render_conic");
    levels = worker.getLev_stack();
    arc = worker.getBez_stack();
    arc[arcIdx + 0].x = RasterUtil.UPSCALE(to.x);
    arc[arcIdx + 0].y = RasterUtil.UPSCALE(to.y);
    arc[arcIdx + 1].x = RasterUtil.UPSCALE(control.x);
    arc[arcIdx + 1].y = RasterUtil.UPSCALE(control.y);
    arc[arcIdx + 2].x = worker.getX();
    arc[arcIdx + 2].y = worker.getY();
    top = 0;
    dx = FTCalc.FT_ABS(arc[arcIdx + 2].x + arc[arcIdx + 0].x - 2 * arc[arcIdx + 1].x);
    dy = FTCalc.FT_ABS(arc[arcIdx + 2].y + arc[arcIdx + 0].y - 2 * arc[arcIdx + 1].y);
    if (dx < dy) {
      dx = dy;
    }
    if (dx < RasterUtil.ONE_PIXEL() / 4) {
      doDraw = true;
    }
    if (!doDraw) {
        /* short-cut the arc that crosses the current band */
      min = max = arc[arcIdx + 0].y;
      y = arc[arcIdx + 1].y;
      if (y < min) {
        min = y;
      }
      if (y > max) {
        max = y;
      }
      y = arc[arcIdx + 2].y;
      if (y < min) {
        min = y;
      }
      if (y > max) {
        max = y;
      }
      if (RasterUtil.TRUNC(min) >= worker.getMax_ey() || RasterUtil.TRUNC(max) < worker.getMin_ey()) {
................................................................................
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic !doDraw continue level: %d", level));
          continue;
        }
      }
      doDraw = false;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic call gray_render_line top: %d", top));

      gray_render_line(worker, arc[arcIdx + 0].x, arc[arcIdx + 0].y);
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic call after gray_render_line top: %d", top));
      top--;
      arcIdx -= 2;
    } while ( top >= 0 );
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic end top: %d", top));
  }

................................................................................
Debug(0, DebugTag.DBG_RENDER, TAG, "gray_split_cubic");
    FTVectorRec[] base = base_ref.Get();
    int a;
    int b;
    int c;
    int d;

    base[arcIdx + 6].x = base[arcIdx + 3].x;
    c = base[arcIdx + 1].x;
    d = base[arcIdx + 2].x;
    base[arcIdx + 1].x = a = (base[arcIdx + 0].x + c) / 2;

    base[arcIdx + 5].x = b = (base[arcIdx + 3].x + d) / 2;

    c = (c + d) / 2;
    base[arcIdx + 2].x = a = (a + c) / 2;

    base[arcIdx + 4].x = b = (b + c) / 2;
    base[arcIdx + 3].x = (a + b) / 2;
    base[arcIdx + 6].y = base[arcIdx + 3].y;

    c = base[arcIdx + 1].y;
    d = base[arcIdx + 2].y;
    base[arcIdx + 1].y = a = (base[arcIdx + 0].y + c) / 2;

    base[arcIdx + 5].y = b = (base[arcIdx + 3].y + d) / 2;

    c = (c + d) / 2;
    base[arcIdx + 2].y = a = (a + c) / 2;

    base[arcIdx + 4].y = b = (b + c) / 2;

    base[arcIdx + 3].y = (a + b) / 2;
    base_ref.Set(base);
  }

  /* =====================================================================
   *    gray_render_cubic
   *
   * =====================================================================
................................................................................
    int min;
    int max;
    int y;
    boolean noSplit = false;

Debug(0, DebugTag.DBG_RENDER, TAG, "gray_render_cubic");
    arc = worker.getBez_stack();
    arc[arcIdx + 0].x = RasterUtil.UPSCALE(to.x);
    arc[arcIdx + 0].y = RasterUtil.UPSCALE(to.y);
    arc[arcIdx + 1].x = RasterUtil.UPSCALE(control2.x);
    arc[arcIdx + 1].y = RasterUtil.UPSCALE(control2.y);
    arc[arcIdx + 2].x = RasterUtil.UPSCALE(control1.x);
    arc[arcIdx + 2].y = RasterUtil.UPSCALE(control1.y);
    arc[arcIdx + 3].x = worker.getX();
    arc[arcIdx + 3].y = worker.getY();
      /* Short-cut the arc that crosses the current band. */
    min = max = arc[arcIdx + 0].y;
    y = arc[arcIdx + 1].y;







    if (y < min) {
      min = y;
    }
    if (y > max) {
      max = y;
    }
    y = arc[arcIdx + 2].y;
    if (y < min) {
      min = y;
    }
    if (y > max) {
      max = y;
    }
    y = arc[arcIdx + 3].y;
    if (y < min) {
      min = y;
    }
    if (y > max) {
      max = y;
    }
    if (RasterUtil.TRUNC(min) >= worker.getMax_ey() || RasterUtil.TRUNC(max) < worker.getMin_ey()) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_cubic call gray_render_line"));
      gray_render_line(worker, arc[arcIdx + 0].x, arc[arcIdx + 0].y);
      if (arc == worker.getBez_stack()) {
        return;
      }
      arcIdx -= 3;
    }
    for (;;) {
        /* Decide whether to split or draw. See `Rapid Termination          */
................................................................................
        int dx2;
        int dy2;
        int L;
        int s;
        int s_limit;

          /* dx and dy are x and y components of the P0-P3 chord vector. */
        dx = arc[arcIdx + 3].x - arc[arcIdx + 0].x;
        dy = arc[arcIdx + 3].y - arc[arcIdx + 0].y;
          /* L is an (under)estimate of the Euclidean distance P0-P3.       */
          /*                                                                */
          /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated   */
          /* with least maximum error by                                    */
          /*                                                                */
          /*   r_upperbound = dx + (sqrt(2) - 1) * dy  ,                    */
          /*                                                                */
................................................................................
          arc = arc_ref.Get();
          arcIdx += 3;
          continue;
        }
          /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
        s_limit = L * (RasterUtil.ONE_PIXEL() / 6);
          /* s is L * the perpendicular distance from P1 to the line P0-P3. */
        dx1 = arc[arcIdx + 1].x - arc[arcIdx + 0].x;
        dy1 = arc[arcIdx + 1].y - arc[arcIdx + 0].y;
        s = FTCalc.FT_ABS(dy * dx1 - dx * dy1);
        if (s > s_limit) {
          arc_ref.Set(arc);
          gray_split_cubic(arc_ref, arcIdx);
          arc = arc_ref.Get();
          arcIdx += 3;
          continue;
        }
          /* s is L * the perpendicular distance from P2 to the line P0-P3. */
        dx2 = arc[arcIdx + 2].x - arc[arcIdx + 0].x;
        dy2 = arc[arcIdx + 2].y - arc[arcIdx + 0].y;
        s = FTCalc.FT_ABS(dy * dx2 - dx * dy2);
        if (s > s_limit) {
          arc_ref.Set(arc);
          gray_split_cubic(arc_ref, arcIdx);
          arc = arc_ref.Get();
          arcIdx += 3;
          continue;
................................................................................
        arc_ref.Set(arc);
        gray_split_cubic(arc_ref, arcIdx);
        arc = arc_ref.Get();
        arcIdx += 3;
        continue;
      }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_cubic 2 call gray_render_line"));
      gray_render_line(worker, arc[arcIdx + 0].x, arc[arcIdx + 0].y);
      if (arc == worker.getBez_stack()) {
        return;
      }
      arcIdx -= 3;
      worker.setBez_stack(arc);
    }
  }
................................................................................
    if (outline.getN_points() <= 0) {
      worker.setMin_ex(0);
      worker.setMax_ex(0);
      worker.setMin_ey(0);
      worker.setMax_ey(0);
      return;
    }
    worker.setMin_ex(outline.getPoints()[vecIdx].x);
    worker.setMax_ex(outline.getPoints()[vecIdx].x);
    worker.setMin_ey(outline.getPoints()[vecIdx].y);
    worker.setMax_ey(outline.getPoints()[vecIdx].y);
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("cbox01: %d %d %d %d", worker.getMin_ex(), worker.getMin_ey(), worker.getMax_ex(), worker.getMax_ey()));
    vecIdx++;
    for ( ; vecIdx < limit; vecIdx++) {
      vec = outline.getPoints()[vecIdx];
      int x = vec.x;
      int y = vec.y;

      if (x < worker.getMin_ex()) {
        worker.setMin_ex(x);
      }
      if (x > worker.getMax_ex()) {
        worker.setMax_ex(x);
      }







|




|
|












|



|







 







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







 







|
|
|
|
|
|

|
|








|
|






|







 







|







 







|
|
|
|
>
|
>

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

|
>
|
>
|







 







|
|
|
|
|
|
|
|

|
|
>
>
>
>
>
>
>






<
<
<
<
<
<
<
|








|







 







|
|







 







|
|









|
|







 







|







 







|
|
|
|




|
|







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
98
99
100
101
102
...
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
...
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
623
624
...
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
...
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
747
748
749
750
751
752
753
754
755
756
757
758
759
...
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
...
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
...
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
   *
   * =====================================================================
   */
  private FTError.ErrorTag gray_move_to(FTVectorRec to, grayTWorkerRec worker) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    int x;
    int y;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_move_to: to.x: %d, to.y: %d", to.getX(), to.getY()));

      /* record current cell, if any */
    gray_record_cell(worker);
      /* start to a new position */
    x = RasterUtil.UPSCALE(to.getX());
    y = RasterUtil.UPSCALE(to.getY());
    gray_start_cell(worker, RasterUtil.TRUNC(x), RasterUtil.TRUNC(y));
    worker.setX(x);
    worker.setY(y);
    return error;
  }

  /* =====================================================================
   *    gray_line_to
   *
   * =====================================================================
   */
  private FTError.ErrorTag gray_line_to(FTVectorRec to, grayTWorkerRec worker) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_line_to: to.x: %d, to.y: %d", to.getX(), to.getY()));
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    Debug(0, DebugTag.DBG_RENDER, TAG, "gray_line_to call gray_render_line");
    gray_render_line(worker, RasterUtil.UPSCALE(to.getX()), RasterUtil.UPSCALE(to.getY()));
    Debug(0, DebugTag.DBG_RENDER, TAG, "gray_line_to after call gray_render_line");
    return error;
  }

  /* =====================================================================
   *    gray_conic_to
   *
................................................................................
   */
  private void gray_split_conic(FTReference<FTVectorRec[]> base_ref, int arcIdx) {
Debug(0, DebugTag.DBG_RENDER, TAG, "gray_split_conic");
    FTVectorRec[] base = base_ref.Get();
    int a;
    int b;

    base[arcIdx + 4].setX(base[arcIdx + 2].getX());
    b = base[arcIdx + 1].getX();
    base[arcIdx + 3].setX((base[arcIdx + 2].getX() + b) / 2);
    a = base[arcIdx + 3].getX();
    base[arcIdx + 1].setX((base[arcIdx + 0].getX() + b) / 2);
    b = base[arcIdx + 1].getX();
    base[arcIdx + 2].setX((a + b) / 2);
    base[arcIdx + 4].setY(base[arcIdx + 2].getY());
    b = base[arcIdx + 1].getY();
    base[arcIdx + 3].setY((base[arcIdx + 2].getY() + b) / 2);
    a = base[arcIdx + 3].getY();
    base[arcIdx + 1].setY((base[arcIdx + 0].getY() + b) / 2);
    b = base[arcIdx + 1].getY();
    base[arcIdx + 2].setY((a + b) / 2);
    base_ref.Set(base);
  }

  /* =====================================================================
   *    gray_render_conic
   *
   * =====================================================================
................................................................................
    FTReference<FTVectorRec[]> arc_ref = new FTReference<FTVectorRec[]>();
    int arcIdx = 0;
    boolean doDraw = false;

Debug(0, DebugTag.DBG_RENDER, TAG, "gray_render_conic");
    levels = worker.getLev_stack();
    arc = worker.getBez_stack();
    arc[arcIdx + 0].setX(RasterUtil.UPSCALE(to.getX()));
    arc[arcIdx + 0].setY(RasterUtil.UPSCALE(to.getY()));
    arc[arcIdx + 1].setX(RasterUtil.UPSCALE(control.getX()));
    arc[arcIdx + 1].setY(RasterUtil.UPSCALE(control.getY()));
    arc[arcIdx + 2].setX(worker.getX());
    arc[arcIdx + 2].setY(worker.getY());
    top = 0;
    dx = FTCalc.FT_ABS(arc[arcIdx + 2].getX() + arc[arcIdx].getX() - 2 * arc[arcIdx + 1].getX());
    dy = FTCalc.FT_ABS(arc[arcIdx + 2].getY() + arc[arcIdx].getY() - 2 * arc[arcIdx + 1].getY());
    if (dx < dy) {
      dx = dy;
    }
    if (dx < RasterUtil.ONE_PIXEL() / 4) {
      doDraw = true;
    }
    if (!doDraw) {
        /* short-cut the arc that crosses the current band */
      min = max = arc[arcIdx + 0].getY();
      y = arc[arcIdx + 1].getY();
      if (y < min) {
        min = y;
      }
      if (y > max) {
        max = y;
      }
      y = arc[arcIdx + 2].getY();
      if (y < min) {
        min = y;
      }
      if (y > max) {
        max = y;
      }
      if (RasterUtil.TRUNC(min) >= worker.getMax_ey() || RasterUtil.TRUNC(max) < worker.getMin_ey()) {
................................................................................
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic !doDraw continue level: %d", level));
          continue;
        }
      }
      doDraw = false;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic call gray_render_line top: %d", top));

      gray_render_line(worker, arc[arcIdx + 0].getX(), arc[arcIdx + 0].getY());
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic call after gray_render_line top: %d", top));
      top--;
      arcIdx -= 2;
    } while ( top >= 0 );
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_conic end top: %d", top));
  }

................................................................................
Debug(0, DebugTag.DBG_RENDER, TAG, "gray_split_cubic");
    FTVectorRec[] base = base_ref.Get();
    int a;
    int b;
    int c;
    int d;

    base[arcIdx + 6].setX(base[arcIdx + 3].getX());
    c = base[arcIdx + 1].getX();
    d = base[arcIdx + 2].getX();
    a = (base[arcIdx + 0].getX() + c) / 2;
    base[arcIdx + 1].setX(a);
    b = (base[arcIdx + 3].getX() + d) / 2;
    base[arcIdx + 5].setX(b);
    c = (c + d) / 2;
    a = (a + c) / 2;
    base[arcIdx + 2].setX(a);
    b = (b + c) / 2;
    base[arcIdx + 4].setX(b);
    base[arcIdx + 3].setX((a + b) / 2);
    base[arcIdx + 6].setY(base[arcIdx + 3].getY());
    c = base[arcIdx + 1].getY();
    d = base[arcIdx + 2].getY();
    a = (base[arcIdx + 0].getY() + c) / 2;
    base[arcIdx + 1].setY(a);
    b = (base[arcIdx + 3].getY() + d) / 2;
    base[arcIdx + 5].setY(b);
    c = (c + d) / 2;
    a = (a + c) / 2;
    base[arcIdx + 2].setY(a);
    b = (b + c) / 2;
    base[arcIdx + 4].setY(b);
    base[arcIdx + 3].setY((a + b) / 2);
    base_ref.Set(base);
  }

  /* =====================================================================
   *    gray_render_cubic
   *
   * =====================================================================
................................................................................
    int min;
    int max;
    int y;
    boolean noSplit = false;

Debug(0, DebugTag.DBG_RENDER, TAG, "gray_render_cubic");
    arc = worker.getBez_stack();
    arc[arcIdx + 0].setX(RasterUtil.UPSCALE(to.getX()));
    arc[arcIdx + 0].setY(RasterUtil.UPSCALE(to.getY()));
    arc[arcIdx + 1].setX(RasterUtil.UPSCALE(control2.getX()));
    arc[arcIdx + 1].setY(RasterUtil.UPSCALE(control2.getY()));
    arc[arcIdx + 2].setX(RasterUtil.UPSCALE(control1.getX()));
    arc[arcIdx + 2].setY(RasterUtil.UPSCALE(control1.getY()));
    arc[arcIdx + 3].setX(worker.getX());
    arc[arcIdx + 3].setY(worker.getY());
      /* Short-cut the arc that crosses the current band. */
    min = max = arc[arcIdx + 0].getY();
    y = arc[arcIdx + 1].getY();
    if (y < min) {
      min = y;
    }
    if (y > max) {
      max = y;
    }
    y = arc[arcIdx + 2].getY();
    if (y < min) {
      min = y;
    }
    if (y > max) {
      max = y;
    }







    y = arc[arcIdx + 3].getY();
    if (y < min) {
      min = y;
    }
    if (y > max) {
      max = y;
    }
    if (RasterUtil.TRUNC(min) >= worker.getMax_ey() || RasterUtil.TRUNC(max) < worker.getMin_ey()) {
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_cubic call gray_render_line"));
      gray_render_line(worker, arc[arcIdx].getX(), arc[arcIdx].getY());
      if (arc == worker.getBez_stack()) {
        return;
      }
      arcIdx -= 3;
    }
    for (;;) {
        /* Decide whether to split or draw. See `Rapid Termination          */
................................................................................
        int dx2;
        int dy2;
        int L;
        int s;
        int s_limit;

          /* dx and dy are x and y components of the P0-P3 chord vector. */
        dx = arc[arcIdx + 3].getX() - arc[arcIdx].getX();
        dy = arc[arcIdx + 3].getY() - arc[arcIdx].getY();
          /* L is an (under)estimate of the Euclidean distance P0-P3.       */
          /*                                                                */
          /* If dx >= dy, then r = sqrt(dx^2 + dy^2) can be overestimated   */
          /* with least maximum error by                                    */
          /*                                                                */
          /*   r_upperbound = dx + (sqrt(2) - 1) * dy  ,                    */
          /*                                                                */
................................................................................
          arc = arc_ref.Get();
          arcIdx += 3;
          continue;
        }
          /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
        s_limit = L * (RasterUtil.ONE_PIXEL() / 6);
          /* s is L * the perpendicular distance from P1 to the line P0-P3. */
        dx1 = arc[arcIdx + 1].getX() - arc[arcIdx].getX();
        dy1 = arc[arcIdx + 1].getY() - arc[arcIdx].getY();
        s = FTCalc.FT_ABS(dy * dx1 - dx * dy1);
        if (s > s_limit) {
          arc_ref.Set(arc);
          gray_split_cubic(arc_ref, arcIdx);
          arc = arc_ref.Get();
          arcIdx += 3;
          continue;
        }
          /* s is L * the perpendicular distance from P2 to the line P0-P3. */
        dx2 = arc[arcIdx + 2].getX() - arc[arcIdx].getX();
        dy2 = arc[arcIdx + 2].getY() - arc[arcIdx].getY();
        s = FTCalc.FT_ABS(dy * dx2 - dx * dy2);
        if (s > s_limit) {
          arc_ref.Set(arc);
          gray_split_cubic(arc_ref, arcIdx);
          arc = arc_ref.Get();
          arcIdx += 3;
          continue;
................................................................................
        arc_ref.Set(arc);
        gray_split_cubic(arc_ref, arcIdx);
        arc = arc_ref.Get();
        arcIdx += 3;
        continue;
      }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("gray_render_cubic 2 call gray_render_line"));
      gray_render_line(worker, arc[arcIdx + 0].getX(), arc[arcIdx + 0].getY());
      if (arc == worker.getBez_stack()) {
        return;
      }
      arcIdx -= 3;
      worker.setBez_stack(arc);
    }
  }
................................................................................
    if (outline.getN_points() <= 0) {
      worker.setMin_ex(0);
      worker.setMax_ex(0);
      worker.setMin_ey(0);
      worker.setMax_ey(0);
      return;
    }
    worker.setMin_ex(outline.getPoints()[vecIdx].getX());
    worker.setMax_ex(outline.getPoints()[vecIdx].getX());
    worker.setMin_ey(outline.getPoints()[vecIdx].getY());
    worker.setMax_ey(outline.getPoints()[vecIdx].getY());
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("cbox01: %d %d %d %d", worker.getMin_ex(), worker.getMin_ey(), worker.getMax_ex(), worker.getMax_ey()));
    vecIdx++;
    for ( ; vecIdx < limit; vecIdx++) {
      vec = outline.getPoints()[vecIdx];
      int x = vec.getX();
      int y = vec.getY();

      if (x < worker.getMin_ex()) {
        worker.setMin_ex(x);
      }
      if (x > worker.getMax_ex()) {
        worker.setMax_ex(x);
      }

Changes to aftraster/FTRaster1RendererClass.java.

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        /* raster5 is only capable of producing 5-gray-levels bitmaps */
      if (render.module_clazz.getModule_name() == "raster5")
        return FTError.ErrorTag.GLYPH_CANNOT_RENDER_GLYPH;
    }
    outline = slot.getOutline();
      /* translate the outline to the new origin if needed */
    if (origin != null) {
      outline.OutlineTranslate(origin.x, origin.y);
    }
      /* compute the control box, and grid fit it */
    cbox_ref.Set(cbox);
    outline.FTOutlineGetCBox(cbox_ref);
    cbox = cbox_ref.Get();
      /* undocumented but confirmed: bbox values get rounded */
    cbox.setxMin(FTCalc.FT_PIX_ROUND(cbox.getxMin()));







|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        /* raster5 is only capable of producing 5-gray-levels bitmaps */
      if (render.module_clazz.getModule_name() == "raster5")
        return FTError.ErrorTag.GLYPH_CANNOT_RENDER_GLYPH;
    }
    outline = slot.getOutline();
      /* translate the outline to the new origin if needed */
    if (origin != null) {
      outline.OutlineTranslate(origin.getX(), origin.getY());
    }
      /* compute the control box, and grid fit it */
    cbox_ref.Set(cbox);
    outline.FTOutlineGetCBox(cbox_ref);
    cbox = cbox_ref.Get();
      /* undocumented but confirmed: bbox values get rounded */
    cbox.setxMin(FTCalc.FT_PIX_ROUND(cbox.getxMin()));

Changes to aftraster/FTSmoothRendererClass.java.

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
    }
      /* check rendering mode */
    if (mode != required_mode) {
      return FTError.ErrorTag.GLYPH_CANNOT_RENDER_GLYPH;
    }
      /* translate the outline to the new origin if needed */
    if (origin != null) {
      slot.getOutline().OutlineTranslate(origin.x, origin.y);
      have_translated_origin = true;
    }
      /* compute the control box, and grid fit it */
    cbox_ref.Set(cbox);
    slot.getOutline().FTOutlineGetCBox(cbox_ref);
    cbox = cbox_ref.Get();
      /* undocumented but confirmed: bbox values get rounded */
................................................................................
      /* render outline into bitmap */
    error = render.rasterRender(render.getRaster(), params);
    if (error != FTError.ErrorTag.ERR_OK) {
      if (have_outline_shifted) {
        slot.getOutline().OutlineTranslate(x_shift, y_shift);
      }
      if (have_translated_origin) {
        slot.getOutline().OutlineTranslate(-origin.x, -origin.y);
      }
      if (have_buffer) {
//          FT_FREE( bitmap.buffer );
        slot.getInternal().setFlags(FTTags.GlyphFormat.getTableTag(slot.getInternal().getFlags().getVal() & ~FTTags.GlyphFormat.OWN_BITMAP.getVal()));
      }
      return error;
    }
................................................................................
      have_buffer = false;
      error = FTError.ErrorTag.ERR_OK;
    }
    if (have_outline_shifted) {
      slot.getOutline().OutlineTranslate(x_shift, y_shift);
    }
    if (have_translated_origin) {
      slot.getOutline().OutlineTranslate(-origin.x, -origin.y);
    }
    if (have_buffer) {
//        FT_FREE( bitmap.buffer );
      slot.getInternal().setFlags(FTTags.GlyphFormat.getTableTag(slot.getInternal().getFlags().getVal() & ~FTTags.GlyphFormat.OWN_BITMAP.getVal()));
    }
    return error;
  }
................................................................................
    Log.e(TAG, "gteGlyphCBox not yet implemented");
    return FTError.ErrorTag.ERR_OK;
//    return ft_smooth_get_cbox();
  }

  /* ==================== setMode ===================================== */
  @Override
  public FTError.ErrorTag setMode(FTRendererRec renderer, FTParameter.ParamTag tag, Object data) {
    Log.e(TAG, "setMode not yet implemented");
    return FTError.ErrorTag.ERR_OK;
//    return ft_smooth_set_mode();
  }

  /* ==================== rasterNew ===================================== */
  @Override







|







 







|







 







|







 







|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
...
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
    }
      /* check rendering mode */
    if (mode != required_mode) {
      return FTError.ErrorTag.GLYPH_CANNOT_RENDER_GLYPH;
    }
      /* translate the outline to the new origin if needed */
    if (origin != null) {
      slot.getOutline().OutlineTranslate(origin.getX(), origin.getY());
      have_translated_origin = true;
    }
      /* compute the control box, and grid fit it */
    cbox_ref.Set(cbox);
    slot.getOutline().FTOutlineGetCBox(cbox_ref);
    cbox = cbox_ref.Get();
      /* undocumented but confirmed: bbox values get rounded */
................................................................................
      /* render outline into bitmap */
    error = render.rasterRender(render.getRaster(), params);
    if (error != FTError.ErrorTag.ERR_OK) {
      if (have_outline_shifted) {
        slot.getOutline().OutlineTranslate(x_shift, y_shift);
      }
      if (have_translated_origin) {
        slot.getOutline().OutlineTranslate(-origin.getX(), -origin.getY());
      }
      if (have_buffer) {
//          FT_FREE( bitmap.buffer );
        slot.getInternal().setFlags(FTTags.GlyphFormat.getTableTag(slot.getInternal().getFlags().getVal() & ~FTTags.GlyphFormat.OWN_BITMAP.getVal()));
      }
      return error;
    }
................................................................................
      have_buffer = false;
      error = FTError.ErrorTag.ERR_OK;
    }
    if (have_outline_shifted) {
      slot.getOutline().OutlineTranslate(x_shift, y_shift);
    }
    if (have_translated_origin) {
      slot.getOutline().OutlineTranslate(-origin.getX(), -origin.getY());
    }
    if (have_buffer) {
//        FT_FREE( bitmap.buffer );
      slot.getInternal().setFlags(FTTags.GlyphFormat.getTableTag(slot.getInternal().getFlags().getVal() & ~FTTags.GlyphFormat.OWN_BITMAP.getVal()));
    }
    return error;
  }
................................................................................
    Log.e(TAG, "gteGlyphCBox not yet implemented");
    return FTError.ErrorTag.ERR_OK;
//    return ft_smooth_get_cbox();
  }

  /* ==================== setMode ===================================== */
  @Override
  public FTError.ErrorTag setMode(FTRendererRec renderer, FTParameterRec.ParamTag tag, Object data) {
    Log.e(TAG, "setMode not yet implemented");
    return FTError.ErrorTag.ERR_OK;
//    return ft_smooth_set_mode();
  }

  /* ==================== rasterNew ===================================== */
  @Override

Changes to aftsfnt/FTSfntInterfaceClass.java.

29
30
31
32
33
34
35
36
37
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
65
66
67
68
69
70
71
72
73
74
75
76
77
...
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
...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
import org.apwtcl.apwfreetypelib.aftbase.*;
import org.apwtcl.apwfreetypelib.afttruetype.TTCMapRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTFaceRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTTags;
import org.apwtcl.apwfreetypelib.aftutil.*;

public class FTSfntInterfaceClass extends FTModuleInterface {
    private static int oid = 0;

    private int id;
    private final static String TAG = "FTSfntInterfaceClass";

    /* ==================== FTSfntInterfaceClass =========================== */
    public FTSfntInterfaceClass() {
      oid++;
      id = oid;
      

    }

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

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      return str.toString();
    }

  /* =====================================================================
   * sfnt_init_face
   * =====================================================================
   */
  public FTError.ErrorTag sfnt_init_face(FTStreamRec stream, TTFaceRec ttface, int face_index,
                                         int num_params, FTParameter[] params) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTLibraryRec library = ttface.getDriver().library;
    FTSfntInterfaceClass sfnt;

    if (num_params != 0) ; // unused
    if (params == null) ;  // unused
    Debug(0, DebugTag.DBG_INIT, TAG, "sfnt_init_face called: "+face_index+"!"+ttface.getSfnt()+"!");
................................................................................
    return error;
  }

  /* =====================================================================
   * sfnt_load_face
   * =====================================================================
   */
  public static FTError.ErrorTag sfnt_load_face(FTStreamRec stream, TTFaceRec ttface, int face_index, int num_params, FTParameter[] params) {
    FTError.ErrorTag  error = FTError.ErrorTag.ERR_OK;
    boolean has_outline = false;
    boolean is_apple_sbit = false;
    boolean ignore_preferred_family  = false;
    boolean ignore_preferred_subfamily  = false;

    if (face_index == 0) ; // unused
    FTSfntInterfaceClass sfnt = (FTSfntInterfaceClass)ttface.getSfnt();
      /* Check parameters */
    {
      int i;

      for (i = 0; i < num_params; i++) {
        if (params[i].tag == FTParameter.ParamTag.FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY) {
          ignore_preferred_family = true;
        } else {
          if (params[i].tag == FTParameter.ParamTag.FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY) {
            ignore_preferred_subfamily = true;
          }
        }
      }
    }
      /* Load tables */
      /* We now support two SFNT-based bitmapped font formats.  They */
................................................................................
  public static FTError.ErrorTag sfnt_open_font(FTStreamRec stream, TTFaceRec face) {
    return face.getTtc_header().Load(stream);
  }



  /* ==================== initFace ===================================== */
  public FTError.ErrorTag initFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params, FTParameter[] params) {
    return sfnt_init_face(stream, (TTFaceRec)face, face_index, num_params, params);
  }

  /* ==================== loadFace ===================================== */
  public FTError.ErrorTag loadFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params, FTParameter[] params) {
    return sfnt_load_face(stream, (TTFaceRec)face, face_index, num_params, params);
  }

  /* ==================== gotoTable ===================================== */
  public FTError.ErrorTag gotoTable() {
    Log.e(TAG, "gotoTable not yet implemented");
    return FTError.ErrorTag.ERR_OK;







|

|
|

|
|
|
|
|

<
<
|
|



|
|



|
|
|
|
|






|







 







|













|


|







 







|




|







29
30
31
32
33
34
35
36
37
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
65
66
67
68
69
70
71
72
73
74
75
...
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
...
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
import org.apwtcl.apwfreetypelib.aftbase.*;
import org.apwtcl.apwfreetypelib.afttruetype.TTCMapRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTFaceRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTTags;
import org.apwtcl.apwfreetypelib.aftutil.*;

public class FTSfntInterfaceClass extends FTModuleInterface {
  private static int oid = 0;

  private int id;
  private final static String TAG = "FTSfntInterfaceClass";

  /* ==================== FTSfntInterfaceClass =========================== */
  public FTSfntInterfaceClass() {
    oid++;
    id = oid;
  }



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

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }

  /* =====================================================================
   * sfnt_init_face
   * =====================================================================
   */
  public FTError.ErrorTag sfnt_init_face(FTStreamRec stream, TTFaceRec ttface, int face_index,
                                         int num_params, FTParameterRec[] params) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTLibraryRec library = ttface.getDriver().library;
    FTSfntInterfaceClass sfnt;

    if (num_params != 0) ; // unused
    if (params == null) ;  // unused
    Debug(0, DebugTag.DBG_INIT, TAG, "sfnt_init_face called: "+face_index+"!"+ttface.getSfnt()+"!");
................................................................................
    return error;
  }

  /* =====================================================================
   * sfnt_load_face
   * =====================================================================
   */
  public static FTError.ErrorTag sfnt_load_face(FTStreamRec stream, TTFaceRec ttface, int face_index, int num_params, FTParameterRec[] params) {
    FTError.ErrorTag  error = FTError.ErrorTag.ERR_OK;
    boolean has_outline = false;
    boolean is_apple_sbit = false;
    boolean ignore_preferred_family  = false;
    boolean ignore_preferred_subfamily  = false;

    if (face_index == 0) ; // unused
    FTSfntInterfaceClass sfnt = (FTSfntInterfaceClass)ttface.getSfnt();
      /* Check parameters */
    {
      int i;

      for (i = 0; i < num_params; i++) {
        if (params[i].getTag() == FTParameterRec.ParamTag.FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY) {
          ignore_preferred_family = true;
        } else {
          if (params[i].getTag() == FTParameterRec.ParamTag.FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY) {
            ignore_preferred_subfamily = true;
          }
        }
      }
    }
      /* Load tables */
      /* We now support two SFNT-based bitmapped font formats.  They */
................................................................................
  public static FTError.ErrorTag sfnt_open_font(FTStreamRec stream, TTFaceRec face) {
    return face.getTtc_header().Load(stream);
  }



  /* ==================== initFace ===================================== */
  public FTError.ErrorTag initFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params, FTParameterRec[] params) {
    return sfnt_init_face(stream, (TTFaceRec)face, face_index, num_params, params);
  }

  /* ==================== loadFace ===================================== */
  public FTError.ErrorTag loadFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params, FTParameterRec[] params) {
    return sfnt_load_face(stream, (TTFaceRec)face, face_index, num_params, params);
  }

  /* ==================== gotoTable ===================================== */
  public FTError.ErrorTag gotoTable() {
    Log.e(TAG, "gotoTable not yet implemented");
    return FTError.ErrorTag.ERR_OK;

Changes to aftsfnt/FTSfntTableTag.java.

9
10
11
12
13
14
15
16
17
18
19
20
21
 *  Arnulf Wiedemann: arnulf (at) wiedemann-pri (dot) de
 *
 *  See the file "license.terms" for information on usage and
 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * =====================================================================
 */

import org.apwtcl.apwfreetypelib.aftutil.TTUtil;
import android.util.SparseArray;


public class FTSfntTableTag {
}







<
<
<



9
10
11
12
13
14
15



16
17
18
 *  Arnulf Wiedemann: arnulf (at) wiedemann-pri (dot) de
 *
 *  See the file "license.terms" for information on usage and
 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * =====================================================================
 */





public class FTSfntTableTag {
}

Changes to aftsfnt/SfntModuleClass.java.

25
26
27
28
29
30
31
32
33
34
35
36
37
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
65
66
67
68
69
70
71
72
73
74
75
76
77
import org.apwtcl.apwfreetypelib.aftbase.FTModules;
import org.apwtcl.apwfreetypelib.aftbase.FTRendererRec;
import org.apwtcl.apwfreetypelib.aftbase.FTTags;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;

public class SfntModuleClass extends FTModuleClassRec {
    private static int oid = 0;

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



    /* ==================== SfntModuleClass ================================== */
    public SfntModuleClass() {
      super();
      oid++;
      id = oid;

      module_flags = 0;  /* not a font driver or renderer */
      module_type = FTTags.ModuleType.FT_MODULE;
      module_name = "sfnt";        /* driver name */
      module_version = 0x10000;   /* driver version 1.0 */
      module_requires = 0x20000;  /* driver requires FreeType 2.0 or higher */
      module_interface = new FTSfntInterfaceClass(); /* "Sfnt_Interface"; /* module specific interface */
Debug(0, FTDebug.DebugTag.DBG_INIT, TAG, "SfntModuleClass constructor called!!");
    }
    
    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
    /* ==================== toString ===================================== */
    public String toString() {
      return mySelf()+"!";
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      return str.toString();
    }

  String class_name = "org.apwtcl.gles20.truetype.TTSfntLoad";

  /* ==================== moduleInit ===================================== */
  @Override
  public FTError.ErrorTag moduleInit(FTModuleRec module) {
    Log.i(TAG, "moduleInit");
    // nothing to do
    return FTError.ErrorTag.ERR_OK;







|

|
|

<
<
|
|
|
|
|

|
|
|
|
|
|

|

|
|



|
|



|
|
|
|
|
<
<







25
26
27
28
29
30
31
32
33
34
35
36


37
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
65
66


67
68
69
70
71
72
73
import org.apwtcl.apwfreetypelib.aftbase.FTModules;
import org.apwtcl.apwfreetypelib.aftbase.FTRendererRec;
import org.apwtcl.apwfreetypelib.aftbase.FTTags;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;

public class SfntModuleClass extends FTModuleClassRec {
  private static int oid = 0;

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



  /* ==================== SfntModuleClass ================================== */
  public SfntModuleClass() {
    super();
    oid++;
    id = oid;

    module_flags = 0;  /* not a font driver or renderer */
    module_type = FTTags.ModuleType.FT_MODULE;
    module_name = "sfnt";        /* driver name */
    module_version = 0x10000;   /* driver version 1.0 */
    module_requires = 0x20000;  /* driver requires FreeType 2.0 or higher */
    module_interface = new FTSfntInterfaceClass(); /* "Sfnt_Interface"; /* module specific interface */
Debug(0, FTDebug.DebugTag.DBG_INIT, TAG, "SfntModuleClass constructor called!!");
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
  /* ==================== toString ===================================== */
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }



  /* ==================== moduleInit ===================================== */
  @Override
  public FTError.ErrorTag moduleInit(FTModuleRec module) {
    Log.i(TAG, "moduleInit");
    // nothing to do
    return FTError.ErrorTag.ERR_OK;

Changes to aftsfnt/TTLoad.java.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
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
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
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
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

import android.util.Log;

import org.apwtcl.apwfreetypelib.afttruetype.*;
import org.apwtcl.apwfreetypelib.aftutil.*;

/* ===================================================================== */
/*    TTLoad                                 */
/*                                     */
/* ===================================================================== */

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

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

    /* ==================== TTLoad ================================== */
    public TTLoad() {
      oid++;
      id = oid;
    }

    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG + "!" + id + "!";
    }

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

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf() + "\n");
      return str.toString();
    }

    /*
     * =====================================================================
     * tt_face_load_any
     * 
     * <Description> Loads any font table into client memory.
     * 
     * <Input> face :: The face object to look for.
     * 
     * tag :: The tag of table to load. Use the value 0 if you want to access
     * the whole font file, else set this parameter to a valid TrueType table
     * tag that you can forge with the MAKE_TT_TAG macro.
     * 
     * offset :: The starting offset in the table (or the file if tag == 0).
     * 
     * length :: The address of the decision variable:
     * 
     * If length == NULL: Loads the whole table. Returns an error if `offset' ==
     * 0!
     * 
     * If *length == 0: Exits immediately; returning the length of the given
     * table or of the font file, depending on the value of `tag'.
     * 
     * If *length != 0: Loads the next `length' bytes of table or font, starting
     * at offset `offset' (in table or font too).
     * 
     * <Output> buffer :: The address of target buffer.
     * 
     * <Return> FreeType error code. 0 means success.
     * 
     * =====================================================================
     */
    public static FTError.ErrorTag tt_face_load_any(Object... args) {
      TTFaceRec face = (TTFaceRec) args[0];
      TTTags.Table tag = (TTTags.Table) args[1];
      long offset = (long) args[2];
      byte[] buffer = (byte[]) args[3];
      FTReference<Long> length_ref = (FTReference<Long>) args[4];
      long length = length_ref.Get();

      FTError.ErrorTag error;
      FTStreamRec stream;
      TTTableRec table;
      Long size;

      if (tag != TTTags.Table.unkn) {
        /* look for tag in font directory */
        table = face.lookupTable(tag);
        if (table == null) {
          error = FTError.ErrorTag.LOAD_TABLE_MISSING;
          return error;
        }
        offset += table.getOffset();
        size = (long) table.getLength();
      } else {
        /* tag == 0 -- the user wants to access the font file directly */
    	  size = face.getStream().getSize();
      }
      if (length_ref != null && length == 0) {
        length = size;
        length_ref.Set(length);
        return FTError.ErrorTag.ERR_OK;
      }
      if (length_ref != null) {
        size = length;
      }
      stream = face.getStream();
      /* the `if' is syntactic sugar for picky compilers */
      stream.seek(offset);
      int ret = stream.readByteArray(buffer, size.shortValue());
      if (ret > 0) {
        error = FTError.ErrorTag.ERR_OK;
      } else {
        error = FTError.ErrorTag.LOAD_STREAM_READ_ERROR;
      }
      return error;
    }

    /*
     * =====================================================================
     * tt_face_free_name
     * 
     * <Description> Frees the name records.
     * 
     * <Input> face :: A handle to the target face object.
     * 
     * =====================================================================
     */
    public static void tt_face_free_name(Object... args) {
      FTReference<TTFaceRec> face_ref = (FTReference<TTFaceRec>) args[0];

      TTFaceRec face = face_ref.Get();
      TTNameTableRec table = face.getName_table();
      TTNameEntryRec entry = null;
      int count = table.getNumNameRecords();

      if (table.getNames() != null) {
        for (int i = 0; i < count; i++) {
          // FT_FREE( entry.string );
          entry = table.getNames()[i];
          entry.setStringLength(0);
        }
        /* free strings table */
        // FT_FREE(table.names);
      }
      table.reset();
      face.setName_table(table);
      face_ref.Set(face);
    }

    /*
     * =====================================================================
     * load_sbit_image
     * =====================================================================
     */
    public static int load_sbit_image(Object... arg1) {
      Log.e(TAG, "load_sbit_image not yet implemented");
      return 1;
    }


    /*
     * =====================================================================
     * tt_face_load_sbit_image
     * =====================================================================
     */
    public static int tt_face_load_sbit_image(Object... arg1) {
      Log.e(TAG, "tt_face_load_sbit_image not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_get_ps_name
     * =====================================================================
     */
    public static int tt_face_get_psname(Object... arg1) {
      Log.e(TAG, "tt_face_get_psname not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_free_ps_name
     * =====================================================================
     */
    public static int tt_face_free_ps_names(Object... arg1) {
      Log.e(TAG, "tt_face_free_ps_names not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_get_kerning
     * =====================================================================
     */
    public static int tt_face_get_kerning(Object... arg1) {
      Log.e(TAG, "tt_face_get_kerning not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_load_eblc
     * =====================================================================
     */
    public static int tt_face_load_eblc(Object... arg1) {
      Log.e(TAG, "tt_face_load_eblc not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_free_eblc
     * =====================================================================
     */
    public static int tt_face_free_eblc(Object... arg1) {
      Log.e(TAG, "tt_face_free_eblc not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_set_bit_strike
     * =====================================================================
     */
    public static int tt_face_set_bit_strike(Object... arg1) {
      Log.e(TAG, "tt_face_set_bit_strike not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_load_strike_metrics
     * =====================================================================
     */
    public static int tt_face_load_strike_metrics(Object... arg1) {
      Log.e(TAG, "tt_face_load_strike_metrics not yet implemented");
      return 1;
    }

    /* =====================================================================
     * tt_face_get_metrics
     *
     * <Description>
     *    Returns the horizontal or vertical metrics in font units for a
     *    given glyph.  The metrics are the left side bearing (resp. top
     *    side bearing) and advance width (resp. advance height).
     *
     * <Input>
     *    header  :: A pointer to either the horizontal or vertical metrics
     *               structure.
     *
     *    idx     :: The glyph index.
     *
     * <Output>
     *    bearing :: The bearing, either left side or top side.
     *
     *    advance :: The advance width resp. advance height.
     * 
     * =====================================================================
     */
    public static FTError.ErrorTag tt_face_get_metrics(Object ... args) {
      TTFaceRec face = (TTFaceRec)args[0];
      boolean vertical = (boolean)args[1];
      int gindex = (int)args[2];
      FTReference<Short> bearing_ref = (FTReference<Short>)args[3];
      FTReference<Short> advance_ref = (FTReference<Short>)args[4];
      long table_pos;
      int table_size;
      long table_end;
      long pos;
      int advance;
      int bearing;
      int k;

      if (vertical) {
        table_pos = face.getVert_metrics_header().getMetricsOffset();
        table_size = face.getVert_metrics_header().getMetricsSize();
        k = face.getVertical().getNumberOfVMetrics();
      } else {
        table_pos = face.getHori_metrics_header().getMetricsOffset();
        table_size = face.getHori_metrics_header().getMetricsSize();
        k = face.getHorizontal().getNumberOfHMetrics();
      }
      table_end = table_pos + table_size;
      if (k > 0) {
        if (gindex < (int)k) {
          table_pos += 4 * gindex;
          if (table_pos + 4 > table_end) {
            bearing_ref.Set((short)0);
            advance_ref.Set((short)0);
            return FTError.ErrorTag.ERR_OK;
          }
          pos = face.getStream().seek(table_pos);
          advance = face.getStream().readShort();
          bearing = face.getStream().readShort();
          if (pos < 0 /* ||
               FT_READ_USHORT(*aadvance) ||
               FT_READ_SHORT(*abearing) */ ) {
            bearing_ref.Set((short)0);
            advance_ref.Set((short)0);
            return FTError.ErrorTag.ERR_OK;
          }
          advance_ref.Set((short)advance);
          bearing_ref.Set((short)bearing);
        } else {
          table_pos += 4 * (k - 1);
          if (table_pos + 4 > table_end) {
            bearing_ref.Set((short)0);
            advance_ref.Set((short)0);
            return FTError.ErrorTag.ERR_OK;
          }
          pos = face.getStream().seek(table_pos);
          advance = face.getStream().readShort();
          if (pos < 0 /* ||
               FT_READ_USHORT(*aadvance) */ ) {
            bearing_ref.Set((short)0);
            advance_ref.Set((short)0);
            return FTError.ErrorTag.ERR_OK;
          }
          advance_ref.Set((short)advance);
          table_pos += 4 + 2 * (gindex - k);
          if (table_pos + 2 > table_end) {
            bearing_ref.Set((short)0);
          } else {
            pos = face.getStream().seek(table_pos);
            bearing = face.getStream().readShort();
            bearing_ref.Set((short)bearing);
          }
        }
      } else {
        bearing_ref.Set((short)0);
        advance_ref.Set((short)0);
      }
      return FTError.ErrorTag.ERR_OK;
    }

    /* =====================================================================
     * tt_face_get_device_metrics
     *
     * Return the advance width table for a given pixel size if it is found
     * in the font's `hdmx' table (if any).
     *
     * =====================================================================
     */
    public static int tt_face_get_device_metrics(TTFaceRec face, int ppem, int gindex) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_face_device_metrics");
      int nn;
      int result = 0;
      long record_size = face.getHdmx_table().getRecordSize();
      int recordIdx = 8;
      // face.hdmx_table

      for (nn = 0; nn < face.getHdmx_table().getRecordCount(); nn++) {
        if (face.getHdmx_table().getRecordValue(nn) == ppem) {
          gindex += 2;
          if (gindex < record_size) {
            result = (int)(recordIdx + nn * record_size + gindex);
          }
          break;
        }
      }
      return result;
    }

    /* =====================================================================
     * tt_face_get_location
     *
     * =====================================================================
     */
    public static long tt_face_get_location(TTFaceRec face, int gindex, FTReference<Integer> size_ref) {
      long pos1;
      long pos2;
      int pIdx;
      int pLimit;
      FTReference<Integer> idx_ref = new FTReference<Integer>();
//      p -> face.glyph_locations

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_face_get_location: num_location: "+face.getLoca_table().getNum_locations()+"!");
      pos1 = 0;
      pos2 = 0;
      if (gindex < face.getLoca_table().getNum_locations()) {
        if (face.getHeader().getIndexToLocFormat() != 0) {
          pIdx = gindex * 4;
          pLimit = (face.getLoca_table().getNum_locations() * 4);
          idx_ref.Set(pIdx);
          pos1 = FTUtil.FT_NEXT_ULONG(face.getGlyph_locations(), idx_ref, pLimit);
          pIdx = idx_ref.Get();
          pos2 = pos1;
          if (pIdx + 4 <= pLimit) {
            idx_ref.Set(pIdx);
            pos2 = FTUtil.FT_NEXT_ULONG(face.getGlyph_locations(), idx_ref, pLimit);
            pIdx = idx_ref.Get();
          }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("posa: pIdx: %d pLimit: %d pos1: %d pos2: %d", pIdx, pLimit, pos1, pos2));
        } else {
          pIdx = gindex * 2;
          pLimit = (face.getLoca_table().getNum_locations() * 2);
          idx_ref.Set(pIdx);
          pos1 = FTUtil.FT_NEXT_USHORT(face.getLoca_table().getGlyph_locations(), idx_ref, pLimit);
          pIdx = idx_ref.Get();
          pos2 = pos1;
          if (pIdx + 2 <= pLimit) {
            idx_ref.Set(pIdx);
            pos2 = FTUtil.FT_NEXT_USHORT(face.getLoca_table().getGlyph_locations(), idx_ref, pLimit);
            pIdx = idx_ref.Get();
          }
          pos1 <<= 1;
          pos2 <<= 1;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("posb: pIdx: %d pLimit: %d %d %d", pIdx, pLimit, pos1, pos2));
        }
      }
      /* Check broken location data */
      if (pos1 > face.getLoca_table().getGlyf_len()) {
        FTTrace.Trace(7, TAG, String.format("tt_face_get_location: too large offset=0x%08lx "+
               "found for gid=0x%04x, exceeding the end of glyf table (0x%08x)",
               pos1, gindex, face.getLoca_table().getGlyf_len()));
        size_ref.Set(0);
        return 0;
      }
      if (pos2 > face.getLoca_table().getGlyf_len()) {
        FTTrace.Trace(7, TAG, String.format("tt_face_get_location:"+
                    " too large offset=0x%08x found for gid=0x%04x,"+
                    " truncate at the end of glyf table (0x%08x)",
                    pos2, gindex + 1, face.getLoca_table().getGlyf_len()));
        pos2 = face.getLoca_table().getGlyf_len();
      }
      /* The `loca' table must be ordered; it refers to the length of */
      /* an entry as the difference between the current and the next  */
      /* position.  However, there do exist (malformed) fonts which   */
      /* don't obey this rule, so we are only able to provide an      */
      /* upper bound for the size.                                    */
      /*                                                              */
      /* We get (intentionally) a wrong, non-zero result in case the  */
      /* `glyf' table is missing.                                     */
      if (pos2 >= pos1) {
        size_ref.Set((int)(pos2 - pos1));
      } else {
        size_ref.Set((int)(face.getLoca_table().getGlyf_len() - pos1));
      }
      return pos1;
    }

}







|
|



|

|
|

|
|
|
|
|

|
|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
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
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
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
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


import android.util.Log;

import org.apwtcl.apwfreetypelib.afttruetype.*;
import org.apwtcl.apwfreetypelib.aftutil.*;

/* ===================================================================== */
/*    TTLoad                                                             */
/*                                                                       */
/* ===================================================================== */

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

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

  /* ==================== TTLoad ================================== */
  public TTLoad() {
    oid++;
    id = oid;
  }

  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG + "!" + id + "!";
    }

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

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf() + "\n");
    return str.toString();
  }

  /*
   * =====================================================================
   * tt_face_load_any
   * 
   * <Description> Loads any font table into client memory.
   * 
   * <Input> face :: The face object to look for.
   * 
   * tag :: The tag of table to load. Use the value 0 if you want to access
   * the whole font file, else set this parameter to a valid TrueType table
   * tag that you can forge with the MAKE_TT_TAG macro.
   * 
   * offset :: The starting offset in the table (or the file if tag == 0).
   * 
   * length :: The address of the decision variable:
   * 
   * If length == NULL: Loads the whole table. Returns an error if `offset' ==
   * 0!
   * 
   * If *length == 0: Exits immediately; returning the length of the given
   * table or of the font file, depending on the value of `tag'.
   * 
   * If *length != 0: Loads the next `length' bytes of table or font, starting
   * at offset `offset' (in table or font too).
   * 
   * <Output> buffer :: The address of target buffer.
   * 
   * <Return> FreeType error code. 0 means success.
   * 
   * =====================================================================
   */
  public static FTError.ErrorTag tt_face_load_any(Object... args) {
    TTFaceRec face = (TTFaceRec) args[0];
    TTTags.Table tag = (TTTags.Table) args[1];
    long offset = (long) args[2];
    byte[] buffer = (byte[]) args[3];
    FTReference<Long> length_ref = (FTReference<Long>) args[4];
    long length = length_ref.Get();

    FTError.ErrorTag error;
    FTStreamRec stream;
    TTTableRec table;
    Long size;

    if (tag != TTTags.Table.unkn) {
      /* look for tag in font directory */
      table = face.lookupTable(tag);
      if (table == null) {
        error = FTError.ErrorTag.LOAD_TABLE_MISSING;
        return error;
      }
      offset += table.getOffset();
      size = (long) table.getLength();
    } else {
      /* tag == 0 -- the user wants to access the font file directly */
  	  size = face.getStream().getSize();
    }
    if (length_ref != null && length == 0) {
      length = size;
      length_ref.Set(length);
      return FTError.ErrorTag.ERR_OK;
    }
    if (length_ref != null) {
      size = length;
    }
    stream = face.getStream();
    /* the `if' is syntactic sugar for picky compilers */
    stream.seek(offset);
    int ret = stream.readByteArray(buffer, size.shortValue());
    if (ret > 0) {
      error = FTError.ErrorTag.ERR_OK;
    } else {
      error = FTError.ErrorTag.LOAD_STREAM_READ_ERROR;
    }
    return error;
  }

  /*
   * =====================================================================
   * tt_face_free_name
   * 
   * <Description> Frees the name records.
   * 
   * <Input> face :: A handle to the target face object.
   * 
   * =====================================================================
   */
  public static void tt_face_free_name(Object... args) {
    FTReference<TTFaceRec> face_ref = (FTReference<TTFaceRec>) args[0];

    TTFaceRec face = face_ref.Get();
    TTNameTableRec table = face.getName_table();
    TTNameEntryRec entry = null;
    int count = table.getNumNameRecords();

    if (table.getNames() != null) {
      for (int i = 0; i < count; i++) {
        // FT_FREE( entry.string );
        entry = table.getNames()[i];
        entry.setStringLength(0);
      }
      /* free strings table */
      // FT_FREE(table.names);
    }
    table.reset();
    face.setName_table(table);
    face_ref.Set(face);
  }

  /*
   * =====================================================================
   * load_sbit_image
   * =====================================================================
   */
  public static int load_sbit_image(Object... arg1) {
    Log.e(TAG, "load_sbit_image not yet implemented");
    return 1;
  }

  /*
   * =====================================================================
   * tt_face_load_sbit_image
   * =====================================================================
   */
  public static int tt_face_load_sbit_image(Object... arg1) {
    Log.e(TAG, "tt_face_load_sbit_image not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_get_ps_name
   * =====================================================================
   */
  public static int tt_face_get_psname(Object... arg1) {
    Log.e(TAG, "tt_face_get_psname not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_free_ps_name
   * =====================================================================
   */
  public static int tt_face_free_ps_names(Object... arg1) {
    Log.e(TAG, "tt_face_free_ps_names not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_get_kerning
   * =====================================================================
   */
  public static int tt_face_get_kerning(Object... arg1) {
    Log.e(TAG, "tt_face_get_kerning not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_load_eblc
   * =====================================================================
   */
  public static int tt_face_load_eblc(Object... arg1) {
    Log.e(TAG, "tt_face_load_eblc not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_free_eblc
   * =====================================================================
   */
  public static int tt_face_free_eblc(Object... arg1) {
    Log.e(TAG, "tt_face_free_eblc not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_set_bit_strike
   * =====================================================================
   */
  public static int tt_face_set_bit_strike(Object... arg1) {
    Log.e(TAG, "tt_face_set_bit_strike not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_load_strike_metrics
   * =====================================================================
   */
  public static int tt_face_load_strike_metrics(Object... arg1) {
    Log.e(TAG, "tt_face_load_strike_metrics not yet implemented");
    return 1;
  }

  /* =====================================================================
   * tt_face_get_metrics
   *
   * <Description>
   *    Returns the horizontal or vertical metrics in font units for a
   *    given glyph.  The metrics are the left side bearing (resp. top
   *    side bearing) and advance width (resp. advance height).
   *
   * <Input>
   *    header  :: A pointer to either the horizontal or vertical metrics
   *               structure.
   *
   *    idx     :: The glyph index.
   *
   * <Output>
   *    bearing :: The bearing, either left side or top side.
   *
   *    advance :: The advance width resp. advance height.
   * 
   * =====================================================================
   */
  public static FTError.ErrorTag tt_face_get_metrics(Object ... args) {
    TTFaceRec face = (TTFaceRec)args[0];
    boolean vertical = (boolean)args[1];
    int gindex = (int)args[2];
    FTReference<Short> bearing_ref = (FTReference<Short>)args[3];
    FTReference<Short> advance_ref = (FTReference<Short>)args[4];
    long table_pos;
    int table_size;
    long table_end;
    long pos;
    int advance;
    int bearing;
    int k;

    if (vertical) {
      table_pos = face.getVert_metrics_header().getMetricsOffset();
      table_size = face.getVert_metrics_header().getMetricsSize();
      k = face.getVertical().getNumberOfVMetrics();
    } else {
      table_pos = face.getHori_metrics_header().getMetricsOffset();
      table_size = face.getHori_metrics_header().getMetricsSize();
      k = face.getHorizontal().getNumberOfHMetrics();
    }
    table_end = table_pos + table_size;
    if (k > 0) {
      if (gindex < (int)k) {
        table_pos += 4 * gindex;
        if (table_pos + 4 > table_end) {
          bearing_ref.Set((short)0);
          advance_ref.Set((short)0);
          return FTError.ErrorTag.ERR_OK;
        }
        pos = face.getStream().seek(table_pos);
        advance = face.getStream().readShort();
        bearing = face.getStream().readShort();
        if (pos < 0 /* ||
             FT_READ_USHORT(*aadvance) ||
             FT_READ_SHORT(*abearing) */ ) {
          bearing_ref.Set((short)0);
          advance_ref.Set((short)0);
          return FTError.ErrorTag.ERR_OK;
        }
        advance_ref.Set((short)advance);
        bearing_ref.Set((short)bearing);
      } else {
        table_pos += 4 * (k - 1);
        if (table_pos + 4 > table_end) {
          bearing_ref.Set((short)0);
          advance_ref.Set((short)0);
          return FTError.ErrorTag.ERR_OK;
        }
        pos = face.getStream().seek(table_pos);
        advance = face.getStream().readShort();
        if (pos < 0 /* ||
             FT_READ_USHORT(*aadvance) */ ) {
          bearing_ref.Set((short)0);
          advance_ref.Set((short)0);
          return FTError.ErrorTag.ERR_OK;
        }
        advance_ref.Set((short)advance);
        table_pos += 4 + 2 * (gindex - k);
        if (table_pos + 2 > table_end) {
          bearing_ref.Set((short)0);
        } else {
          pos = face.getStream().seek(table_pos);
          bearing = face.getStream().readShort();
          bearing_ref.Set((short)bearing);
        }
      }
    } else {
      bearing_ref.Set((short)0);
      advance_ref.Set((short)0);
    }
    return FTError.ErrorTag.ERR_OK;
  }

  /* =====================================================================
   * tt_face_get_device_metrics
   *
   * Return the advance width table for a given pixel size if it is found
   * in the font's `hdmx' table (if any).
   *
   * =====================================================================
   */
  public static int tt_face_get_device_metrics(TTFaceRec face, int ppem, int gindex) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_face_device_metrics");
    int nn;
    int result = 0;
    long record_size = face.getHdmx_table().getRecordSize();
    int recordIdx = 8;
    // face.hdmx_table

    for (nn = 0; nn < face.getHdmx_table().getRecordCount(); nn++) {
      if (face.getHdmx_table().getRecordValue(nn) == ppem) {
        gindex += 2;
        if (gindex < record_size) {
          result = (int)(recordIdx + nn * record_size + gindex);
        }
        break;
      }
    }
    return result;
  }

  /* =====================================================================
   * tt_face_get_location
   *
   * =====================================================================
   */
  public static long tt_face_get_location(TTFaceRec face, int gindex, FTReference<Integer> size_ref) {
    long pos1;
    long pos2;
    int pIdx;
    int pLimit;
    FTReference<Integer> idx_ref = new FTReference<Integer>();
//      p -> face.glyph_locations

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tt_face_get_location: num_location: "+face.getLoca_table().getNum_locations()+"!");
    pos1 = 0;
    pos2 = 0;
    if (gindex < face.getLoca_table().getNum_locations()) {
      if (face.getHeader().getIndexToLocFormat() != 0) {
        pIdx = gindex * 4;
        pLimit = (face.getLoca_table().getNum_locations() * 4);
        idx_ref.Set(pIdx);
        pos1 = FTUtil.FT_NEXT_ULONG(face.getGlyph_locations(), idx_ref, pLimit);
        pIdx = idx_ref.Get();
        pos2 = pos1;
        if (pIdx + 4 <= pLimit) {
          idx_ref.Set(pIdx);
          pos2 = FTUtil.FT_NEXT_ULONG(face.getGlyph_locations(), idx_ref, pLimit);
          pIdx = idx_ref.Get();
        }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("posa: pIdx: %d pLimit: %d pos1: %d pos2: %d", pIdx, pLimit, pos1, pos2));
      } else {
        pIdx = gindex * 2;
        pLimit = (face.getLoca_table().getNum_locations() * 2);
        idx_ref.Set(pIdx);
        pos1 = FTUtil.FT_NEXT_USHORT(face.getLoca_table().getGlyph_locations(), idx_ref, pLimit);
        pIdx = idx_ref.Get();
        pos2 = pos1;
        if (pIdx + 2 <= pLimit) {
          idx_ref.Set(pIdx);
          pos2 = FTUtil.FT_NEXT_USHORT(face.getLoca_table().getGlyph_locations(), idx_ref, pLimit);
          pIdx = idx_ref.Get();
        }
        pos1 <<= 1;
        pos2 <<= 1;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("posb: pIdx: %d pLimit: %d %d %d", pIdx, pLimit, pos1, pos2));
      }
    }
    /* Check broken location data */
    if (pos1 > face.getLoca_table().getGlyf_len()) {
      FTTrace.Trace(7, TAG, String.format("tt_face_get_location: too large offset=0x%08lx "+
             "found for gid=0x%04x, exceeding the end of glyf table (0x%08x)",
             pos1, gindex, face.getLoca_table().getGlyf_len()));
      size_ref.Set(0);
      return 0;
    }
    if (pos2 > face.getLoca_table().getGlyf_len()) {
      FTTrace.Trace(7, TAG, String.format("tt_face_get_location:"+
                  " too large offset=0x%08x found for gid=0x%04x,"+
                  " truncate at the end of glyf table (0x%08x)",
                  pos2, gindex + 1, face.getLoca_table().getGlyf_len()));
      pos2 = face.getLoca_table().getGlyf_len();
    }
    /* The `loca' table must be ordered; it refers to the length of */
    /* an entry as the difference between the current and the next  */
    /* position.  However, there do exist (malformed) fonts which   */
    /* don't obey this rule, so we are only able to provide an      */
    /* upper bound for the size.                                    */
    /*                                                              */
    /* We get (intentionally) a wrong, non-zero result in case the  */
    /* `glyf' table is missing.                                     */
    if (pos2 >= pos1) {
      size_ref.Set((int)(pos2 - pos1));
    } else {
      size_ref.Set((int)(face.getLoca_table().getGlyf_len() - pos1));
    }
    return pos1;
  }

}

Changes to aftsfnt/TTSfntLoad.java.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
65
66
67
package org.apwtcl.apwfreetypelib.aftsfnt;

  /* ===================================================================== */
  /*    TTSfntLoad                                                         */
  /*                                                                       */
  /* ===================================================================== */

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.FTCharMapRec;
import org.apwtcl.apwfreetypelib.aftbase.FTEncoding;
import org.apwtcl.apwfreetypelib.aftbase.FTFaceRec;
import org.apwtcl.apwfreetypelib.aftbase.FTLibraryRec;
import org.apwtcl.apwfreetypelib.aftbase.FTModuleRec;
import org.apwtcl.apwfreetypelib.aftbase.Flags;
import org.apwtcl.apwfreetypelib.afttruetype.TTFaceRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTNameTableRec;
import org.apwtcl.apwfreetypelib.afttruetype.TTTags;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTParameter;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTStreamRec;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;

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

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

    /* ==================== TTSfntLoad ================================== */
    public TTSfntLoad() {
      oid++;
      id = oid;
    }
    
    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
    /* ==================== toString ===================================== */
    public String toString() {
      return mySelf()+"!";
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      return str.toString();
    }
 
}







<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<


|

|
|

|
|
|
|
|

|
|



|
|



|
|
|
|
|


14
15
16
17
18
19
20











21





22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package org.apwtcl.apwfreetypelib.aftsfnt;

  /* ===================================================================== */
  /*    TTSfntLoad                                                         */
  /*                                                                       */
  /* ===================================================================== */












import org.apwtcl.apwfreetypelib.aftutil.FTDebug;






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

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

  /* ==================== TTSfntLoad ================================== */
  public TTSfntLoad() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
  /* ==================== toString ===================================== */
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }
 
}

Changes to afttruetype/TTDefaultGraphicsStateClass.java.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    oid++;
    id = oid;

    rp0 = 0;
    rp1 = 0;
    rp2 = 0;
    dualVector = new FTVectorRec();
    dualVector.x = 0x4000;
    dualVector.y = 0;
    projVector = new FTVectorRec();
    projVector.x = 0x4000;
    projVector.y = 0;
    freeVector = new FTVectorRec();
    freeVector.x = 0x4000;
    freeVector.y = 0;

    loop = 1;
    minimum_distance = 64;
    round_state = TTInterpTags.Round.To_Grid;

    auto_flip = true;
    control_value_cutin = 68;







|
|

|
|

|
|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    oid++;
    id = oid;

    rp0 = 0;
    rp1 = 0;
    rp2 = 0;
    dualVector = new FTVectorRec();
    dualVector.setX(0x4000);
    dualVector.setY(0);
    projVector = new FTVectorRec();
    projVector.setX(0x4000);
    projVector.setY(0);
    freeVector = new FTVectorRec();
    freeVector.setX(0x4000);
    freeVector.setY(0);

    loop = 1;
    minimum_distance = 64;
    round_state = TTInterpTags.Round.To_Grid;

    auto_flip = true;
    control_value_cutin = 68;

Changes to afttruetype/TTDriverClass.java.

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  /*                                                                       */
  /* ===================================================================== */

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.*;
import org.apwtcl.apwfreetypelib.aftsfnt.FTSfntInterfaceClass;
import org.apwtcl.apwfreetypelib.aftttinterpreter.TTOpCode;
import org.apwtcl.apwfreetypelib.aftttinterpreter.TTRunInstructions;
import org.apwtcl.apwfreetypelib.aftutil.*;

public class TTDriverClass extends FTDriverClassRec {
  private static int oid = 0;

  private int id;
................................................................................
   * <InOut>
   *    face       :: The newly built face object.
   *
   * <Return>
   *    FreeType error code.  0 means success.
   * =====================================================================
   */
  private FTError.ErrorTag tt_face_init(FTStreamRec stream, TTFaceRec ttface, int face_index, int num_params, FTParameter[] params) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTLibraryRec library;
    FTSfntInterfaceClass sfnt = null;

Debug(0, DebugTag.DBG_INIT, TAG, "tt_face_init");
    FTTrace.Trace(7, TAG, "TTF driver");
    library = ttface.getDriver().library;
................................................................................
  }

  String face_class_name = "org.apwtcl.gles20.truetype.TTFaceFuncs";

  /* ==================== initFace ===================================== */
  @Override
  public FTError.ErrorTag initFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params,
                                   FTParameter[] params) {
    return tt_face_init(stream, (TTFaceRec)face, face_index, num_params, params);
  }

  /* ==================== doneFace ===================================== */
  @Override
  public void doneFace(FTFaceRec face) {
    tt_face_done((TTFaceRec)face);







<







 







|







 







|







18
19
20
21
22
23
24

25
26
27
28
29
30
31
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  /*                                                                       */
  /* ===================================================================== */

import android.util.Log;

import org.apwtcl.apwfreetypelib.aftbase.*;
import org.apwtcl.apwfreetypelib.aftsfnt.FTSfntInterfaceClass;

import org.apwtcl.apwfreetypelib.aftttinterpreter.TTRunInstructions;
import org.apwtcl.apwfreetypelib.aftutil.*;

public class TTDriverClass extends FTDriverClassRec {
  private static int oid = 0;

  private int id;
................................................................................
   * <InOut>
   *    face       :: The newly built face object.
   *
   * <Return>
   *    FreeType error code.  0 means success.
   * =====================================================================
   */
  private FTError.ErrorTag tt_face_init(FTStreamRec stream, TTFaceRec ttface, int face_index, int num_params, FTParameterRec[] params) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    FTLibraryRec library;
    FTSfntInterfaceClass sfnt = null;

Debug(0, DebugTag.DBG_INIT, TAG, "tt_face_init");
    FTTrace.Trace(7, TAG, "TTF driver");
    library = ttface.getDriver().library;
................................................................................
  }

  String face_class_name = "org.apwtcl.gles20.truetype.TTFaceFuncs";

  /* ==================== initFace ===================================== */
  @Override
  public FTError.ErrorTag initFace(FTStreamRec stream, FTFaceRec face, int face_index, int num_params,
                                   FTParameterRec[] params) {
    return tt_face_init(stream, (TTFaceRec)face, face_index, num_params, params);
  }

  /* ==================== doneFace ===================================== */
  @Override
  public void doneFace(FTFaceRec face) {
    tt_face_done((TTFaceRec)face);

Changes to afttruetype/TTGlyphLoaderFuncs.java.

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
      gloader.getCurrent().getTags()[n_points + 1] = Flags.Curve.CONIC;
      gloader.getCurrent().getTags()[n_points + 2] = Flags.Curve.CONIC;
      gloader.getCurrent().getTags()[n_points + 3] = Flags.Curve.CONIC;
      n_points += 4;
      if ((loader.getLoad_flags().getVal() & Flags.Load.NO_HINTING.getVal()) == 0) {
        loader.getZone().tt_prepare_zone(gloader.getCurrent(), 0, 0);
        for (int i = 0; i < (loader.getZone().getN_points() + 4); i++) {
          loader.getZone().getOrus()[loader.getZone().getOrus_idx() + i] = new FTVectorRec();
          loader.getZone().getOrus()[loader.getZone().getOrus_idx() + i].x = loader.getZone().getCurPoint_x(i);
          loader.getZone().getOrus()[loader.getZone().getOrus_idx() + i].y = loader.getZone().getCurPoint_y(i);
        }
      }
      {
        int vecIdx = 0;
        int limit = n_points;
        int x_scale = 0; /* pacify compiler */
        int y_scale = 0;
................................................................................
            x_scale = ((TTSizeRec)loader.getSize()).getMetrics().getX_scale();
            y_scale = ((TTSizeRec)loader.getSize()).getMetrics().getY_scale();
            do_scale = true;
          }
        }
        if (do_scale) {
          for (vecIdx = 0; vecIdx < limit; vecIdx++) {
            gloader.getCurrent().getPoints()[vecIdx].x = TTUtil.FTMulFix(gloader.getCurrent().getPoints()[vecIdx].x, x_scale);
            gloader.getCurrent().getPoints()[vecIdx].y = TTUtil.FTMulFix(gloader.getCurrent().getPoints()[vecIdx].y, y_scale);
          }
          loader.setPp1(gloader.getCurrent().getPoints()[n_points - 4]);
          loader.setPp2(gloader.getCurrent().getPoints()[n_points - 3]);
          loader.setPp3(gloader.getCurrent().getPoints()[n_points - 2]);
          loader.setPp4(gloader.getCurrent().getPoints()[n_points - 1]);
        }
      }
................................................................................
        /* of the previously loaded components.                             */
        /* change to the point numbers used by our outline */
        k += start_point;
        l += num_base_points;
        if (k >= num_base_points || l >= num_points) {
          return FTError.ErrorTag.GLYPH_INVALID_COMPOSITE;
        }
        x = gloader.getBase().getPoints()[k].x - gloader.getBase().getPoints()[l].x;
        y = gloader.getBase().getPoints()[k].y - gloader.getBase().getPoints()[l].y;
      } else {
        x = subglyph.getArg1();
        y = subglyph.getArg2();
        if (x == 0 && y == 0) {
          return FTError.ErrorTag.ERR_OK;
        }
        /* Use a default value dependent on                                     */
................................................................................
        /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED.  This is useful for old TT */
        /* fonts which don't set the xxx_COMPONENT_OFFSET bit.                  */
        if (have_scale && (subglyph.getFlags().getVal() & Flags.LoadType.SCALED_COMPONENT_OFFSET.getVal()) != 0) {
          /*************************************************************************/
          /*                                                                       */
          /* This algorithm is a guess and works much better than the above.       */
          /*                                                                       */
          int mac_xscale = FTCalc.FTHypot(subglyph.getTransform().xx, subglyph.getTransform().xy);
          int mac_yscale = FTCalc.FTHypot(subglyph.getTransform().yy, subglyph.getTransform().yx);
          x = TTUtil.FTMulFix(x, mac_xscale);
          y = TTUtil.FTMulFix(y, mac_yscale);
        }
        if ((loader.getLoad_flags().getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
          int x_scale = ((TTSizeRec)loader.getSize()).getMetrics().getX_scale();
          int y_scale = ((TTSizeRec)loader.getSize()).getMetrics().getY_scale();
          x = TTUtil.FTMulFix(x, x_scale);







|
|
|







 







|
|







 







|
|







 







|
|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
      gloader.getCurrent().getTags()[n_points + 1] = Flags.Curve.CONIC;
      gloader.getCurrent().getTags()[n_points + 2] = Flags.Curve.CONIC;
      gloader.getCurrent().getTags()[n_points + 3] = Flags.Curve.CONIC;
      n_points += 4;
      if ((loader.getLoad_flags().getVal() & Flags.Load.NO_HINTING.getVal()) == 0) {
        loader.getZone().tt_prepare_zone(gloader.getCurrent(), 0, 0);
        for (int i = 0; i < (loader.getZone().getN_points() + 4); i++) {
          loader.getZone().setOrusPoint(i, new FTVectorRec());
          loader.getZone().getOrusPoint(i).setX(loader.getZone().getCurPoint_x(i));
          loader.getZone().getOrusPoint(i).setY(loader.getZone().getCurPoint_y(i));
        }
      }
      {
        int vecIdx = 0;
        int limit = n_points;
        int x_scale = 0; /* pacify compiler */
        int y_scale = 0;
................................................................................
            x_scale = ((TTSizeRec)loader.getSize()).getMetrics().getX_scale();
            y_scale = ((TTSizeRec)loader.getSize()).getMetrics().getY_scale();
            do_scale = true;
          }
        }
        if (do_scale) {
          for (vecIdx = 0; vecIdx < limit; vecIdx++) {
            gloader.getCurrent().getPoints()[vecIdx].setX(TTUtil.FTMulFix(gloader.getCurrent().getPoints()[vecIdx].getX(), x_scale));
            gloader.getCurrent().getPoints()[vecIdx].setY(TTUtil.FTMulFix(gloader.getCurrent().getPoints()[vecIdx].getY(), y_scale));
          }
          loader.setPp1(gloader.getCurrent().getPoints()[n_points - 4]);
          loader.setPp2(gloader.getCurrent().getPoints()[n_points - 3]);
          loader.setPp3(gloader.getCurrent().getPoints()[n_points - 2]);
          loader.setPp4(gloader.getCurrent().getPoints()[n_points - 1]);
        }
      }
................................................................................
        /* of the previously loaded components.                             */
        /* change to the point numbers used by our outline */
        k += start_point;
        l += num_base_points;
        if (k >= num_base_points || l >= num_points) {
          return FTError.ErrorTag.GLYPH_INVALID_COMPOSITE;
        }
        x = gloader.getBase().getPoints()[k].getX() - gloader.getBase().getPoints()[l].getX();
        y = gloader.getBase().getPoints()[k].getY() - gloader.getBase().getPoints()[l].getY();
      } else {
        x = subglyph.getArg1();
        y = subglyph.getArg2();
        if (x == 0 && y == 0) {
          return FTError.ErrorTag.ERR_OK;
        }
        /* Use a default value dependent on                                     */
................................................................................
        /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED.  This is useful for old TT */
        /* fonts which don't set the xxx_COMPONENT_OFFSET bit.                  */
        if (have_scale && (subglyph.getFlags().getVal() & Flags.LoadType.SCALED_COMPONENT_OFFSET.getVal()) != 0) {
          /*************************************************************************/
          /*                                                                       */
          /* 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 ((loader.getLoad_flags().getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
          int x_scale = ((TTSizeRec)loader.getSize()).getMetrics().getX_scale();
          int y_scale = ((TTSizeRec)loader.getSize()).getMetrics().getY_scale();
          x = TTUtil.FTMulFix(x, x_scale);

Changes to afttruetype/TTGlyphLoaderRec.java.

150
151
152
153
154
155
156
157
158
159
160
161
162
    vec_limit = n_points;
    for (vec_idx = 0; vec_idx < vec_limit; vec_idx++) {
      current.getPoints()[vec_idx] = ttglyph.getPoints()[vec_idx];
    }
    current.setN_points(n_points);
    current.setN_contours(n_contours);
for (int i = 0; i < n_points; i++) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("point i:%d  %d %d", i, current.getPoints()[i].x, current.getPoints()[i].y));
}
    return error;
  }

}







|





150
151
152
153
154
155
156
157
158
159
160
161
162
    vec_limit = n_points;
    for (vec_idx = 0; vec_idx < vec_limit; vec_idx++) {
      current.getPoints()[vec_idx] = ttglyph.getPoints()[vec_idx];
    }
    current.setN_points(n_points);
    current.setN_contours(n_contours);
for (int i = 0; i < n_points; i++) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("point i:%d  %d %d", i, current.getPoints()[i].getX(), current.getPoints()[i].getY()));
}
    return error;
  }

}

Changes to afttruetype/TTGlyphSimpleRec.java.

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
            return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
          }
          delta = (short)stream.readShort();
        }
      }
      x += delta;
      x_coordinates[vec_idx] = delta;
      points[vec_idx].x = x;
      tags[tag_idx] = (byte)(tag & ~(TTTags.GlyphFlags.X_SHORT.getVal() | TTTags.GlyphFlags.X_SAME.getVal()));
      tag_idx++;
    }

    /* reading the Y coordinates */
    y_coordinates = new int[num_points];
    vec_idx = 0;
................................................................................
            return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
          }
          delta = (short)stream.readShort();
        }
      }
      y += delta;
      y_coordinates[vec_idx] = delta;
      points[vec_idx].y = y;
      tags[tag_idx] = (byte)(tag & ~(TTTags.GlyphFlags.Y_SHORT.getVal() | TTTags.GlyphFlags.Y_SAME.getVal()));
      tag_idx++;
    }

    FTTrace.Trace(7, TAG, "loaded");
    Debug(0, DebugTag.DBG_LOAD_FACE, TAG, toDebugString());
    return error;







|







 







|







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
            return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
          }
          delta = (short)stream.readShort();
        }
      }
      x += delta;
      x_coordinates[vec_idx] = delta;
      points[vec_idx].setX(x);
      tags[tag_idx] = (byte)(tag & ~(TTTags.GlyphFlags.X_SHORT.getVal() | TTTags.GlyphFlags.X_SAME.getVal()));
      tag_idx++;
    }

    /* reading the Y coordinates */
    y_coordinates = new int[num_points];
    vec_idx = 0;
................................................................................
            return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
          }
          delta = (short)stream.readShort();
        }
      }
      y += delta;
      y_coordinates[vec_idx] = delta;
      points[vec_idx].setY(y);
      tags[tag_idx] = (byte)(tag & ~(TTTags.GlyphFlags.Y_SHORT.getVal() | TTTags.GlyphFlags.Y_SAME.getVal()));
      tag_idx++;
    }

    FTTrace.Trace(7, TAG, "loaded");
    Debug(0, DebugTag.DBG_LOAD_FACE, TAG, toDebugString());
    return error;

Changes to afttruetype/TTGlyphSlotRec.java.

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
        outline = loader.getGloader().getBase();
        outline.setFlags(outline.getFlags() & ~Flags.Outline.SINGLE_PASS.getVal());
          /* Translate array so that (0,0) is the glyph's origin.  Note  */
          /* that this behaviour is independent on the value of bit 1 of */
          /* the `flags' field in the `head' table -- at least major     */
          /* applications like Acroread indicate that.                   */
//          showLoaderZone("TTLoadGlyph");
        Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader.pp1.x: %d", loader.getPp1().x));
        int i;
        for (i = 0; i < loader.getGloader().getCurrent().getN_points() + 4; i++) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("PP1: i: %d ipoints_idx: %d x: %d y: %d\n", i, loader.getGloader().getCurrent().getPoints_idx(), loader.getGloader().getCurrent().getPoint(i).x,
              loader.getGloader().getCurrent().getPoint(i).y));
        }
        if (loader.getPp1().x != 0) {
          outline.OutlineTranslate(-loader.getPp1().x, 0);
        }
      }

      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "IS_HINTED: "+((load_flags & Flags.Load.NO_HINTING.getVal()) == 0));
      if ((load_flags & Flags.Load.NO_HINTING.getVal()) == 0) {
        if (loader.getExec().graphics_state.isScan_control()) {
            /* convert scan conversion mode to FT_OUTLINE_XXX flags */







|


|
|

|
|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
        outline = loader.getGloader().getBase();
        outline.setFlags(outline.getFlags() & ~Flags.Outline.SINGLE_PASS.getVal());
          /* Translate array so that (0,0) is the glyph's origin.  Note  */
          /* that this behaviour is independent on the value of bit 1 of */
          /* the `flags' field in the `head' table -- at least major     */
          /* applications like Acroread indicate that.                   */
//          showLoaderZone("TTLoadGlyph");
        Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader.pp1.x: %d", loader.getPp1().getX()));
        int i;
        for (i = 0; i < loader.getGloader().getCurrent().getN_points() + 4; i++) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("PP1: i: %d ipoints_idx: %d x: %d y: %d\n", i, loader.getGloader().getCurrent().getPoints_idx(), loader.getGloader().getCurrent().getPoint(i).getX(),
              loader.getGloader().getCurrent().getPoint(i).getY()));
        }
        if (loader.getPp1().getX() != 0) {
          outline.OutlineTranslate(-loader.getPp1().getX(), 0);
        }
      }

      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "IS_HINTED: "+((load_flags & Flags.Load.NO_HINTING.getVal()) == 0));
      if ((load_flags & Flags.Load.NO_HINTING.getVal()) == 0) {
        if (loader.getExec().graphics_state.isScan_control()) {
            /* convert scan conversion mode to FT_OUTLINE_XXX flags */

Changes to afttruetype/TTGlyphZoneRec.java.

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
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
...
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
512
...
523
524
525
526
527
528
529
530
531
532
533
534
535
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
565
566
567
568
569
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "loaderZone.org: "+org+"!"+org_idx);
    }
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "Show loaderZone");
    for (j = 0; j < n_points; j++) {
      if (cur != null) {
        if (j < cur.length) {
          if (cur[cur_idx + j] != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  cur: %d %5d %5d", j, cur[cur_idx + j].x, cur[cur_idx + j].y));
          }
        }
      }
      if (orus != null) {
        if (j < orus.length) {
          if (orus[orus_idx + j] != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" orus: %d %5d %5d", j, orus[orus_idx + j].x, orus[orus_idx + j].y));
          }
        }
      }
      if (org != null) {
        if (j < org.length) {
          if (org[org_idx + j] != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  org: %d %5d %5d", j, org[org_idx + j].x, org[org_idx + j].y));
          }
        }
      }
    }
  }

  /* ==================== showLoaderZoneShort ================================== */
  public void showLoaderZoneShort(String str) {
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("%s: n_points: %d", str, n_points));
    int n_points = 5;
    for( int j = 0; j < n_points; j++) {
      if (cur != null) {
        if (j < cur.length) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  cur: %d %5d %5d", j, cur[cur_idx + j].x, cur[cur_idx + j].y));
        }
      }
      if (orus != null) {
        if (j < orus.length) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" orus: %d %5d %5d", j, orus[orus_idx + j].x, orus[orus_idx + j].y));
        }
      }
      if (org != null) {
        if (j < org.length) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  org: %d %5d %5d", j, org[org_idx + j].x, org[org_idx + j].y));
        }
      }
    }
  }

  /* =====================================================================
   * reset
................................................................................
    max_points = 0;
    max_contours = 0;
    n_points = 0;
    n_contours = 0;

    if (org != null) {
      for (i = 0; i < org.length; i++) {
        org[i].x = 0;
        org[i].y = 0;
      }
    }
    org_idx = 0;

    if (cur != null) {
      for (i = 0; i < cur.length; i++) {
        cur[i].x = 0;
        cur[i].y = 0;
      }
    }
    cur_idx = 0;

    if (orus != null) {
      for (i = 0; i < orus.length; i++) {
        orus[i].x = 0;
        orus[i].y = 0;
      }
    }
    orus_idx = 0;

    if (tags != null) {
      for (i = 0; i < tags.length; i++) {
        tags[i] = Flags.Curve.CONIC;
................................................................................
  /* ==================== getOrgPoint ================================== */
  public FTVectorRec getOrgPoint(int point_idx) {
    return org[org_idx + point_idx];
  }

  /* ==================== getOrgPoint_x ================================== */
  public int getOrgPoint_x(int point_idx) {
    return org[org_idx + point_idx].x;
  }

  /* ==================== getOrgPoint_y ================================== */
  public int getOrgPoint_y(int point_idx) {
    return org[org_idx + point_idx].y;
  }

  /* ==================== setOrg ================================== */
  public void xsetOrg(FTVectorRec[] org) {
    this.org = org;
  }

  /* ==================== setOrgPoint ================================== */
  public void setOrgPoint(int point_idx, FTVectorRec vec) {
    org[org_idx + point_idx].x = vec.x;
    org[org_idx + point_idx].y = vec.y;
  }

  /* ==================== setOrgPoint_x ================================== */
  public void setOrgPoint_x(int point_idx, int value) {
    org[org_idx + point_idx].x = value;
  }

  /* ==================== setOrgPoint_y ================================== */
  public void setOrgPoint_y(int point_idx, int value) {
    org[org_idx + point_idx].y = value;
  }

  /* ==================== resetOrgPoint ================================== */
  public void resetOrgPoint(int point_idx) {
    org[org_idx + point_idx].x = 0;
    org[org_idx + point_idx].y = 0;
  }

  /* ==================== getOrg_idx ================================== */
  public int getOrg_idx() {
    return org_idx;
  }

................................................................................
  /* ==================== getCurPoint ================================== */
  public FTVectorRec getCurPoint(int point_idx) {
    return cur[cur_idx + point_idx];
  }

  /* ==================== getCurPoint_x ================================== */
  public int getCurPoint_x(int point_idx) {
    return cur[cur_idx + point_idx].x;
  }

  /* ==================== getCurPoint_y ================================== */
  public int getCurPoint_y(int point_idx) {
    return cur[cur_idx + point_idx].y;
  }

  /* ==================== setCur ================================== */
  public void xsetCur(FTVectorRec[] cur) {
    this.cur = cur;
  }

  /* ==================== setCurPoint ================================== */
  public void setCurPoint(int point_idx, FTVectorRec vec) {
    cur[cur_idx + point_idx].x = vec.x;
    cur[cur_idx + point_idx].y = vec.y;
  }

  /* ==================== setCurPoint_x ================================== */
  public void setCurPoint_x(int point_idx, int value) {
    cur[cur_idx + point_idx].x = value;
  }

  /* ==================== setCurPoint_y ================================== */
  public void setCurPoint_y(int point_idx, int value) {
    cur[cur_idx + point_idx].y = value;
  }

  /* ==================== resetCurPoint ================================== */
  public void resetCurPoint(int point_idx) {
    cur[cur_idx + point_idx].x = 0;
    cur[cur_idx + point_idx].y = 0;
  }

  /* ==================== getCur_idx ================================== */
  public int getCur_idx() {
    return cur_idx;
  }

................................................................................
  /* ==================== getOrusPoint ================================== */
  public FTVectorRec getOrusPoint(int point_idx) {
    return orus[orus_idx + point_idx];
  }

  /* ==================== getOrusPoint_x ================================== */
  public int getOrusPoint_x(int point_idx) {
    return orus[orus_idx + point_idx].x;
  }

  /* ==================== getOrusPoint_y ================================== */
  public int getOrusPoint_y(int point_idx) {
    return orus[orus_idx + point_idx].y;
  }

  /* ==================== setOrus ================================== */
  public void xsetOrus(FTVectorRec[] orus) {
    this.orus = orus;
  }

  /* ==================== setOrusPoint ================================== */
  public void setOrusPoint(int point_idx, FTVectorRec vec) {
    orus[orus_idx + point_idx].x = vec.x;
    orus[orus_idx + point_idx].y = vec.y;
  }

  /* ==================== setOrusPoint_x ================================== */
  public void setOrusPoint_x(int point_idx, int value) {
    orus[orus_idx + point_idx].x = value;
  }

  /* ==================== setOrusPoint_y ================================== */
  public void setOrusPoint_y(int point_idx, int value) {
    orus[orus_idx + point_idx].y = value;
  }

  /* ==================== resetOrusPoint ================================== */
  public void resetOrusPoint(int point_idx) {
    orus[orus_idx + point_idx].x = 0;
    orus[orus_idx + point_idx].y = 0;
  }

  /* ==================== getOrus_idx ================================== */
  public int getOrus_idx() {
    return orus_idx;
  }








|






|






|













|




|




|







 







|
|






|
|






|
|







 







|




|









|
|




|




|




|
|







 







|




|









|
|




|




|




|
|







 







|




|









|
|




|




|




|
|







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
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
...
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
512
...
523
524
525
526
527
528
529
530
531
532
533
534
535
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
565
566
567
568
569
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "loaderZone.org: "+org+"!"+org_idx);
    }
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "Show loaderZone");
    for (j = 0; j < n_points; j++) {
      if (cur != null) {
        if (j < cur.length) {
          if (cur[cur_idx + j] != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  cur: %d %5d %5d", j, cur[cur_idx + j].getX(), cur[cur_idx + j].getY()));
          }
        }
      }
      if (orus != null) {
        if (j < orus.length) {
          if (orus[orus_idx + j] != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" orus: %d %5d %5d", j, orus[orus_idx + j].getX(), orus[orus_idx + j].getY()));
          }
        }
      }
      if (org != null) {
        if (j < org.length) {
          if (org[org_idx + j] != null) {
            Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  org: %d %5d %5d", j, org[org_idx + j].getX(), org[org_idx + j].getY()));
          }
        }
      }
    }
  }

  /* ==================== showLoaderZoneShort ================================== */
  public void showLoaderZoneShort(String str) {
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("%s: n_points: %d", str, n_points));
    int n_points = 5;
    for( int j = 0; j < n_points; j++) {
      if (cur != null) {
        if (j < cur.length) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  cur: %d %5d %5d", j, cur[cur_idx + j].getX(), cur[cur_idx + j].getY()));
        }
      }
      if (orus != null) {
        if (j < orus.length) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format(" orus: %d %5d %5d", j, orus[orus_idx + j].getX(), orus[orus_idx + j].getY()));
        }
      }
      if (org != null) {
        if (j < org.length) {
          Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("  org: %d %5d %5d", j, org[org_idx + j].getX(), org[org_idx + j].getY()));
        }
      }
    }
  }

  /* =====================================================================
   * reset
................................................................................
    max_points = 0;
    max_contours = 0;
    n_points = 0;
    n_contours = 0;

    if (org != null) {
      for (i = 0; i < org.length; i++) {
        org[i].setX(0);
        org[i].setY(0);
      }
    }
    org_idx = 0;

    if (cur != null) {
      for (i = 0; i < cur.length; i++) {
        cur[i].setX(0);
        cur[i].setY(0);
      }
    }
    cur_idx = 0;

    if (orus != null) {
      for (i = 0; i < orus.length; i++) {
        orus[i].setX(0);
        orus[i].setY(0);
      }
    }
    orus_idx = 0;

    if (tags != null) {
      for (i = 0; i < tags.length; i++) {
        tags[i] = Flags.Curve.CONIC;
................................................................................
  /* ==================== getOrgPoint ================================== */
  public FTVectorRec getOrgPoint(int point_idx) {
    return org[org_idx + point_idx];
  }

  /* ==================== getOrgPoint_x ================================== */
  public int getOrgPoint_x(int point_idx) {
    return org[org_idx + point_idx].getX();
  }

  /* ==================== getOrgPoint_y ================================== */
  public int getOrgPoint_y(int point_idx) {
    return org[org_idx + point_idx].getY();
  }

  /* ==================== setOrg ================================== */
  public void xsetOrg(FTVectorRec[] org) {
    this.org = org;
  }

  /* ==================== setOrgPoint ================================== */
  public void setOrgPoint(int point_idx, FTVectorRec vec) {
    org[org_idx + point_idx].setX(vec.getX());
    org[org_idx + point_idx].setY(vec.getY());
  }

  /* ==================== setOrgPoint_x ================================== */
  public void setOrgPoint_x(int point_idx, int value) {
    org[org_idx + point_idx].setX(value);
  }

  /* ==================== setOrgPoint_y ================================== */
  public void setOrgPoint_y(int point_idx, int value) {
    org[org_idx + point_idx].setY(value);
  }

  /* ==================== resetOrgPoint ================================== */
  public void resetOrgPoint(int point_idx) {
    org[org_idx + point_idx].setX(0);
    org[org_idx + point_idx].setY(0);
  }

  /* ==================== getOrg_idx ================================== */
  public int getOrg_idx() {
    return org_idx;
  }

................................................................................
  /* ==================== getCurPoint ================================== */
  public FTVectorRec getCurPoint(int point_idx) {
    return cur[cur_idx + point_idx];
  }

  /* ==================== getCurPoint_x ================================== */
  public int getCurPoint_x(int point_idx) {
    return cur[cur_idx + point_idx].getX();
  }

  /* ==================== getCurPoint_y ================================== */
  public int getCurPoint_y(int point_idx) {
    return cur[cur_idx + point_idx].getY();
  }

  /* ==================== setCur ================================== */
  public void xsetCur(FTVectorRec[] cur) {
    this.cur = cur;
  }

  /* ==================== setCurPoint ================================== */
  public void setCurPoint(int point_idx, FTVectorRec vec) {
    cur[cur_idx + point_idx].setX(vec.getX());
    cur[cur_idx + point_idx].setY(vec.getY());
  }

  /* ==================== setCurPoint_x ================================== */
  public void setCurPoint_x(int point_idx, int value) {
    cur[cur_idx + point_idx].setX(value);
  }

  /* ==================== setCurPoint_y ================================== */
  public void setCurPoint_y(int point_idx, int value) {
    cur[cur_idx + point_idx].setY(value);
  }

  /* ==================== resetCurPoint ================================== */
  public void resetCurPoint(int point_idx) {
    cur[cur_idx + point_idx].setX(0);
    cur[cur_idx + point_idx].setY(0);
  }

  /* ==================== getCur_idx ================================== */
  public int getCur_idx() {
    return cur_idx;
  }

................................................................................
  /* ==================== getOrusPoint ================================== */
  public FTVectorRec getOrusPoint(int point_idx) {
    return orus[orus_idx + point_idx];
  }

  /* ==================== getOrusPoint_x ================================== */
  public int getOrusPoint_x(int point_idx) {
    return orus[orus_idx + point_idx].getX();
  }

  /* ==================== getOrusPoint_y ================================== */
  public int getOrusPoint_y(int point_idx) {
    return orus[orus_idx + point_idx].getY();
  }

  /* ==================== setOrus ================================== */
  public void xsetOrus(FTVectorRec[] orus) {
    this.orus = orus;
  }

  /* ==================== setOrusPoint ================================== */
  public void setOrusPoint(int point_idx, FTVectorRec vec) {
    orus[orus_idx + point_idx].setX(vec.getX());
    orus[orus_idx + point_idx].setY(vec.getY());
  }

  /* ==================== setOrusPoint_x ================================== */
  public void setOrusPoint_x(int point_idx, int value) {
    orus[orus_idx + point_idx].setX(value);
  }

  /* ==================== setOrusPoint_y ================================== */
  public void setOrusPoint_y(int point_idx, int value) {
    orus[orus_idx + point_idx].setY(value);
  }

  /* ==================== resetOrusPoint ================================== */
  public void resetOrusPoint(int point_idx) {
    orus[orus_idx + point_idx].setX(0);
    orus[orus_idx + point_idx].setY(0);
  }

  /* ==================== getOrus_idx ================================== */
  public int getOrus_idx() {
    return orus_idx;
  }

Changes to afttruetype/TTIUPWorkerRec.java.

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
128
129
130
131
132
133
134
135
136
137
138
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
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  /* ==================== getOrgPoint ================================== */
  public FTVectorRec getOrgPoint(int point_idx) {
    return org[org_idx + point_idx];
  }

  /* ==================== getOrgPoint_x ================================== */
  public int getOrgPoint_x(int point_idx) {
    return org[org_idx + point_idx].x;
  }

  /* ==================== getOrgPoint_y ================================== */
  public int getOrgPoint_y(int point_idx) {
    return org[org_idx + point_idx].y;
  }

  /* ==================== setOrg ================================== */
  public void setOrg(FTVectorRec[] org) {
    this.org = org;
  }

  /* ==================== setOrgPoint ================================== */
  public void setOrgPoint(int point_idx, FTVectorRec vec) {
    org[org_idx + point_idx].x = vec.x;
    org[org_idx + point_idx].y = vec.y;
  }

  /* ==================== setOrgPoint_x ================================== */
  public void setOrgPoint_x(int point_idx, int value) {
    org[org_idx + point_idx].x = value;
  }

  /* ==================== setOrgPoint_y ================================== */
  public void setOrgPoint_y(int point_idx, int value) {
    org[org_idx + point_idx].y = value;
  }

  /* ==================== resetOrgPoint ================================== */
  public void resetOrgPoint(int point_idx) {
    org[org_idx + point_idx].x = 0;
    org[org_idx + point_idx].y = 0;
  }

  /* ==================== getOrg_idx ================================== */
  public int getOrg_idx() {
    return org_idx;
  }

................................................................................
  /* ==================== getCurPoint ================================== */
  public FTVectorRec getCurPoint(int point_idx) {
    return cur[cur_idx + point_idx];
  }

  /* ==================== getCurPoint_x ================================== */
  public int getCurPoint_x(int point_idx) {
    return cur[cur_idx + point_idx].x;
  }

  /* ==================== getCurPoint_y ================================== */
  public int getCurPoint_y(int point_idx) {
    return cur[cur_idx + point_idx].y;
  }

  /* ==================== setCur ================================== */
  public void setCur(FTVectorRec[] cur) {
    this.cur = cur;
  }

  /* ==================== setCurPoint ================================== */
  public void setCurPoint(int point_idx, FTVectorRec vec) {
    cur[cur_idx + point_idx].x = vec.x;
    cur[cur_idx + point_idx].y = vec.y;
  }

  /* ==================== setCurPoint_x ================================== */
  public void setCurPoint_x(int point_idx, int value) {
    cur[cur_idx + point_idx].x = value;
  }

  /* ==================== setCurPoint_y ================================== */
  public void setCurPoint_y(int point_idx, int value) {
    cur[cur_idx + point_idx].y = value;
  }

  /* ==================== resetCurPoint ================================== */
  public void resetCurPoint(int point_idx) {
    cur[cur_idx + point_idx].x = 0;
    cur[cur_idx + point_idx].y = 0;
  }

  /* ==================== getCur_idx ================================== */
  public int getCur_idx() {
    return cur_idx;
  }

................................................................................
  /* ==================== getOrusPoint ================================== */
  public FTVectorRec getOrusPoint(int point_idx) {
    return orus[orus_idx + point_idx];
  }

  /* ==================== getOrusPoint_x ================================== */
  public int getOrusPoint_x(int point_idx) {
    return orus[orus_idx + point_idx].x;
  }

  /* ==================== getOrusPoint_y ================================== */
  public int getOrusPoint_y(int point_idx) {
    return orus[orus_idx + point_idx].y;
  }

  /* ==================== setOrus ================================== */
  public void setOrus(FTVectorRec[] orus) {
    this.orus = orus;
  }

  /* ==================== setOrusPoint ================================== */
  public void setOrusPoint(int point_idx, FTVectorRec vec) {
    orus[orus_idx + point_idx].x = vec.x;
    orus[orus_idx + point_idx].y = vec.y;
  }

  /* ==================== setOrusPoint_x ================================== */
  public void setOrusPoint_x(int point_idx, int value) {
    orus[orus_idx + point_idx].x = value;
  }

  /* ==================== setOrusPoint_y ================================== */
  public void setOrusPoint_y(int point_idx, int value) {
    orus[orus_idx + point_idx].y = value;
  }

  /* ==================== resetOrusPoint ================================== */
  public void resetOrusPoint(int point_idx) {
    orus[orus_idx + point_idx].x = 0;
    orus[orus_idx + point_idx].y = 0;
  }

  /* ==================== getOrus_idx ================================== */
  public int getOrus_idx() {
    return orus_idx;
  }








|




|









|
|




|




|




|
|







 







|




|









|
|




|




|




|
|







 







|




|









|
|




|




|




|
|







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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
128
129
130
131
132
133
134
135
136
137
138
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
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  /* ==================== getOrgPoint ================================== */
  public FTVectorRec getOrgPoint(int point_idx) {
    return org[org_idx + point_idx];
  }

  /* ==================== getOrgPoint_x ================================== */
  public int getOrgPoint_x(int point_idx) {
    return org[org_idx + point_idx].getX();
  }

  /* ==================== getOrgPoint_y ================================== */
  public int getOrgPoint_y(int point_idx) {
    return org[org_idx + point_idx].getY();
  }

  /* ==================== setOrg ================================== */
  public void setOrg(FTVectorRec[] org) {
    this.org = org;
  }

  /* ==================== setOrgPoint ================================== */
  public void setOrgPoint(int point_idx, FTVectorRec vec) {
    org[org_idx + point_idx].setX(vec.getX());
    org[org_idx + point_idx].setY(vec.getY());
  }

  /* ==================== setOrgPoint_x ================================== */
  public void setOrgPoint_x(int point_idx, int value) {
    org[org_idx + point_idx].setX(value);
  }

  /* ==================== setOrgPoint_y ================================== */
  public void setOrgPoint_y(int point_idx, int value) {
    org[org_idx + point_idx].setY(value);
  }

  /* ==================== resetOrgPoint ================================== */
  public void resetOrgPoint(int point_idx) {
    org[org_idx + point_idx].setX(0);
    org[org_idx + point_idx].setY(0);
  }

  /* ==================== getOrg_idx ================================== */
  public int getOrg_idx() {
    return org_idx;
  }

................................................................................
  /* ==================== getCurPoint ================================== */
  public FTVectorRec getCurPoint(int point_idx) {
    return cur[cur_idx + point_idx];
  }

  /* ==================== getCurPoint_x ================================== */
  public int getCurPoint_x(int point_idx) {
    return cur[cur_idx + point_idx].getX();
  }

  /* ==================== getCurPoint_y ================================== */
  public int getCurPoint_y(int point_idx) {
    return cur[cur_idx + point_idx].getY();
  }

  /* ==================== setCur ================================== */
  public void setCur(FTVectorRec[] cur) {
    this.cur = cur;
  }

  /* ==================== setCurPoint ================================== */
  public void setCurPoint(int point_idx, FTVectorRec vec) {
    cur[cur_idx + point_idx].setX(vec.getX());
    cur[cur_idx + point_idx].setY(vec.getY());
  }

  /* ==================== setCurPoint_x ================================== */
  public void setCurPoint_x(int point_idx, int value) {
    cur[cur_idx + point_idx].setX(value);
  }

  /* ==================== setCurPoint_y ================================== */
  public void setCurPoint_y(int point_idx, int value) {
    cur[cur_idx + point_idx].setY(value);
  }

  /* ==================== resetCurPoint ================================== */
  public void resetCurPoint(int point_idx) {
    cur[cur_idx + point_idx].setX(0);
    cur[cur_idx + point_idx].setY(0);
  }

  /* ==================== getCur_idx ================================== */
  public int getCur_idx() {
    return cur_idx;
  }

................................................................................
  /* ==================== getOrusPoint ================================== */
  public FTVectorRec getOrusPoint(int point_idx) {
    return orus[orus_idx + point_idx];
  }

  /* ==================== getOrusPoint_x ================================== */
  public int getOrusPoint_x(int point_idx) {
    return orus[orus_idx + point_idx].getX();
  }

  /* ==================== getOrusPoint_y ================================== */
  public int getOrusPoint_y(int point_idx) {
    return orus[orus_idx + point_idx].getY();
  }

  /* ==================== setOrus ================================== */
  public void setOrus(FTVectorRec[] orus) {
    this.orus = orus;
  }

  /* ==================== setOrusPoint ================================== */
  public void setOrusPoint(int point_idx, FTVectorRec vec) {
    orus[orus_idx + point_idx].setX(vec.getX());
    orus[orus_idx + point_idx].setY(vec.getY());
  }

  /* ==================== setOrusPoint_x ================================== */
  public void setOrusPoint_x(int point_idx, int value) {
    orus[orus_idx + point_idx].setX(value);
  }

  /* ==================== setOrusPoint_y ================================== */
  public void setOrusPoint_y(int point_idx, int value) {
    orus[orus_idx + point_idx].setY(value);
  }

  /* ==================== resetOrusPoint ================================== */
  public void resetOrusPoint(int point_idx) {
    orus[orus_idx + point_idx].setX(0);
    orus[orus_idx + point_idx].setY(0);
  }

  /* ==================== getOrus_idx ================================== */
  public int getOrus_idx() {
    return orus_idx;
  }

Changes to afttruetype/TTLoaderRec.java.

353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
...
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
      /* must initialize points before (possibly) overriding */
      /* glyph metrics from the incremental interface        */

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp1: loader.bbox.xMin: %d, loader.bbox.yMax: %d, loader.left_bearing: %d, loader.top_bearing: %d, loader.vadvance: %d\n", bbox.getxMin(), bbox.getyMax(), left_bearing, top_bearing, vadvance));
      /* Calculate the four phantom points.                     */
      /* The first two stand for horizontal origin and advance. */
      /* The last two stand for vertical origin and advance.    */
      pp1.x = bbox.getxMin() - left_bearing;
      pp1.y = 0;
      pp2.x = pp1.x + advance;
      pp2.y = 0;
      pp3.x = 0;
      pp3.y = top_bearing + bbox.getyMax();
      pp4.x = 0;
      pp4.y = pp3.y - vadvance;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader.pp1.x: %d %d %d %d %d", pp1.x, pp2.x, pp3.y, pp4.y, (load_flags.getVal() & Flags.Load.NO_SCALE.getVal())));
      if ((load_flags.getVal() & Flags.Load.NO_SCALE.getVal()) == 0) {
        pp1.x = TTUtil.FTMulFix(pp1.x, x_scale);
        pp2.x = TTUtil.FTMulFix(pp2.x, x_scale);
        pp3.y = TTUtil.FTMulFix(pp3.y, y_scale);
        pp4.y = TTUtil.FTMulFix(pp4.y, y_scale);
      }
      error = FTError.ErrorTag.ERR_OK;
      if (opened_frame) {
        ttface.forgetGlyphFrame(this);
      }
      return error;
    }
................................................................................
    /* must initialize points before (possibly) overriding */
    /* glyph metrics from the incremental interface        */

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp2: loader.bbox.xMin: %d, loader.bbox.yMax: %d, loader.left_bearing: %d, loader.top_bearing: %d, loader.vadvance: %d\n", bbox.getxMin(), bbox.getyMax(), left_bearing, top_bearing, vadvance));
    /* Calculate the four phantom points.                     */
    /* The first two stand for horizontal origin and advance. */
    /* The last two stand for vertical origin and advance.    */
    pp1.x = bbox.getxMin() - left_bearing;
    pp1.y = 0;
    pp2.x = pp1.x + advance;
    pp2.y = 0;
    pp3.x = 0;
    pp3.y = top_bearing + bbox.getyMax();
    pp4.x = 0;
    pp4.y = pp3.y - vadvance;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp3: 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.x, pp1.y, pp2.x, pp2.y, pp3.x, pp3.y, pp4.x, pp4.y));
    /***********************************************************************/
    /***********************************************************************/
    /***********************************************************************/
    /* if it is a simple glyph, load it */
    if (n_contours > 0) {
      error = gloader.tt_load_simple_glyph(this);
      if (error != FTError.ErrorTag.ERR_OK) {
................................................................................
          return error;
        }
        /* 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.x, pp1.y, pp2.x, pp2.y, pp3.x, pp3.y, pp4.x, pp4.y));
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.x = TTUtil.FTMulFix(pp1.x, x_scale);
          pp2.x = TTUtil.FTMulFix(pp2.x, x_scale);
          pp3.y = TTUtil.FTMulFix(pp3.y, y_scale);
          pp4.y = TTUtil.FTMulFix(pp4.y, 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.x, pp1.y, pp2.x, pp2.y, pp3.x, pp3.y, pp4.x, pp4.y));
        /* 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) {
................................................................................
      bbox = this.bbox;
    }
      /* get the device-independent horizontal advance; it is scaled later */
      /* by the base layer.                                                */
    glyph.setLinearHoriAdvance(linear);
    glyph.getMetrics().setHoriBearingX(bbox.getxMin());
    glyph.getMetrics().setHoriBearingY(bbox.getyMax());
    glyph.getMetrics().setHoriAdvance(pp2.x - pp1.x);
      /* 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) {
................................................................................
      /* create some metrics manually                                   */
    {
      int top;      /* scaled vertical top side bearing  */
      int advance;  /* scaled vertical advance height    */

        /* Get the unscaled top bearing and advance height. */
      if (ttface.isVertical_info() && ttface.getVertical().getNumberOfVMetrics() > 0) {
        top = FTCalc.FTDivFix(pp3.y - bbox.getyMax(), y_scale);
        if (pp3.y <= pp4.y) {
          advance = 0;
        } else {
          advance = FTCalc.FTDivFix(pp3.y - pp4.y, y_scale);
        }
      } else {
        int height;

          /* XXX Compute top side bearing and advance height in  */
          /*     Get_VMetrics instead of here.                   */

................................................................................
  public FTError.ErrorTag HintGlyph(boolean is_composite) {
    FTError.ErrorTag error;
    int origin;
    int n_ins;

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "TTHintGlyph: "+glyph.getControl_len());
    for(int i = 0; i < gloader.getCurrent().getN_points() + 4; i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("PP: %d %d %d\n", i, gloader.getCurrent().getPoints()[i].x,
          gloader.getCurrent().getPoints()[i].y));
    }
    if (glyph.getControl_len() > 0xFFFFL) {
      FTTrace.Trace(7, TAG, "TT_Hint_Glyph: too long instructions ");
      FTTrace.Trace(7, TAG, String.format("(0x%lx byte) is truncated",
          glyph.getControl_len()));
    }
    n_ins = (glyph.getControl_len());
    origin = zone.getCurPoint(zone.getN_points() - 4).x;
    origin = FTCalc.FT_PIX_ROUND(origin) - origin;
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("origin: %d", origin));
    if (origin != 0) {
      FTGlyphLoaderRec.translate_array(zone.getN_points(), zone.getCur(), 0, origin, 0);
    }
    for (int i = 0; i < 5; i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A: i: %d cur.x: %d, cur.y: %d", i, zone.getCurPoint_x(i), zone.getCurPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A: i: %d orus.x: %d, orus.y: %d", i, zone.getOrus()[zone.getOrus_idx() + i].x, zone.getOrus()[zone.getOrus_idx() + i].y));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A: i: %d org.x: %d, org.y: %d", i, zone.getOrgPoint_x(i), zone.getOrgPoint_y(i)));
    }
    for (int i = zone.getN_points() - 4; i < zone.getN_points(); i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A1: i: %d cur.x: %d, cur.y: %d", i, zone.getCurPoint_x(i), zone.getCurPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A1: i: %d orus.x: %d, orus.y: %d", i, zone.getOrus()[zone.getOrus_idx() + i].x, zone.getOrus()[zone.getOrus_idx() + i].y));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A1: i: %d org.x: %d, org.y: %d", i, zone.getOrgPoint_x(i), zone.getOrgPoint_y(i)));
    }
      /* save original point position in org */
    if (n_ins > 0) {
      for (int i = 0; i < (zone.getN_points()); i++) {
        zone.setOrgPoint(i, zone.getCurPoint(i));
      }
    }
    for (int i = 0; i < 5; i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30B: i: %d cur.x: %d, cur.y: %d", i, zone.getCurPoint_x(i), zone.getCurPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30B: i: %d orus.x: %d, orus.y: %d", i, zone.getOrus()[zone.getOrus_idx() + i].x, zone.getOrus()[zone.getOrus_idx() + i].y));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30B: i: %d org.x: %d, org.y: %d", i, zone.getOrgPoint_x(i), zone.getOrgPoint_y(i)));
    }
      /* Reset graphics state. */
    exec.graphics_state = ((TTSizeRec)size).getGraphics_state();
      /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
      /*      completely refer to the (already) hinted subglyphs.     */
    if (is_composite) {







|
|
|
|
|
|
|
|
|

|
|
|
|







 







|
|
|
|
|
|
|
|
|







 







|


|
|
|
|

|







 







|







 







|
|


|







 







|
|







|







|




|










|







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
...
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
...
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
      /* must initialize points before (possibly) overriding */
      /* glyph metrics from the incremental interface        */

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp1: loader.bbox.xMin: %d, loader.bbox.yMax: %d, loader.left_bearing: %d, loader.top_bearing: %d, loader.vadvance: %d\n", bbox.getxMin(), bbox.getyMax(), left_bearing, top_bearing, vadvance));
      /* Calculate the four phantom points.                     */
      /* The first two stand for horizontal origin and advance. */
      /* The last two stand for vertical origin and advance.    */
      pp1.setX(bbox.getxMin() - left_bearing);
      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) {
        ttface.forgetGlyphFrame(this);
      }
      return error;
    }
................................................................................
    /* must initialize points before (possibly) overriding */
    /* glyph metrics from the incremental interface        */

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("loader_set_pp2: loader.bbox.xMin: %d, loader.bbox.yMax: %d, loader.left_bearing: %d, loader.top_bearing: %d, loader.vadvance: %d\n", bbox.getxMin(), bbox.getyMax(), left_bearing, top_bearing, vadvance));
    /* Calculate the four phantom points.                     */
    /* The first two stand for horizontal origin and advance. */
    /* The last two stand for vertical origin and advance.    */
    pp1.setX(bbox.getxMin() - left_bearing);
    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_set_pp3: 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 it is a simple glyph, load it */
    if (n_contours > 0) {
      error = gloader.tt_load_simple_glyph(this);
      if (error != FTError.ErrorTag.ERR_OK) {
................................................................................
          return error;
        }
        /* 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) {
................................................................................
      bbox = this.bbox;
    }
      /* get the device-independent horizontal advance; it is scaled later */
      /* 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) {
................................................................................
      /* create some metrics manually                                   */
    {
      int top;      /* scaled vertical top side bearing  */
      int advance;  /* scaled vertical advance height    */

        /* Get the unscaled top bearing and advance height. */
      if (ttface.isVertical_info() && ttface.getVertical().getNumberOfVMetrics() > 0) {
        top = FTCalc.FTDivFix(pp3.getY() - bbox.getyMax(), y_scale);
        if (pp3.getY() <= pp4.getY()) {
          advance = 0;
        } else {
          advance = FTCalc.FTDivFix(pp3.getY() - pp4.getY(), y_scale);
        }
      } else {
        int height;

          /* XXX Compute top side bearing and advance height in  */
          /*     Get_VMetrics instead of here.                   */

................................................................................
  public FTError.ErrorTag HintGlyph(boolean is_composite) {
    FTError.ErrorTag error;
    int origin;
    int n_ins;

Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "TTHintGlyph: "+glyph.getControl_len());
    for(int i = 0; i < gloader.getCurrent().getN_points() + 4; i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("PP: %d %d %d\n", i, gloader.getCurrent().getPoints()[i].getX(),
          gloader.getCurrent().getPoints()[i].getY()));
    }
    if (glyph.getControl_len() > 0xFFFFL) {
      FTTrace.Trace(7, TAG, "TT_Hint_Glyph: too long instructions ");
      FTTrace.Trace(7, TAG, String.format("(0x%lx byte) is truncated",
          glyph.getControl_len()));
    }
    n_ins = (glyph.getControl_len());
    origin = zone.getCurPoint(zone.getN_points() - 4).getX();
    origin = FTCalc.FT_PIX_ROUND(origin) - origin;
    Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("origin: %d", origin));
    if (origin != 0) {
      FTGlyphLoaderRec.translate_array(zone.getN_points(), zone.getCur(), 0, origin, 0);
    }
    for (int i = 0; i < 5; i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A: i: %d cur.x: %d, cur.y: %d", i, zone.getCurPoint_x(i), zone.getCurPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A: i: %d orus.x: %d, orus.y: %d", i, zone.getOrusPoint_x(i), zone.getOrusPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A: i: %d org.x: %d, org.y: %d", i, zone.getOrgPoint_x(i), zone.getOrgPoint_y(i)));
    }
    for (int i = zone.getN_points() - 4; i < zone.getN_points(); i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A1: i: %d cur.x: %d, cur.y: %d", i, zone.getCurPoint_x(i), zone.getCurPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A1: i: %d orus.x: %d, orus.y: %d", i, zone.getOrusPoint_x(i), zone.getOrusPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30A1: i: %d org.x: %d, org.y: %d", i, zone.getOrgPoint_x(i), zone.getOrgPoint_y(i)));
    }
      /* save original point position in org */
    if (n_ins > 0) {
      for (int i = 0; i < (zone.getN_points()); i++) {
        zone.setOrgPoint(i, zone.getCurPoint(i));
      }
    }
    for (int i = 0; i < 5; i++) {
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30B: i: %d cur.x: %d, cur.y: %d", i, zone.getCurPoint_x(i), zone.getCurPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30B: i: %d orus.x: %d, orus.y: %d", i, zone.getOrusPoint_x(i), zone.getOrusPoint_y(i)));
      Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("TTHintGlyph 30B: i: %d org.x: %d, org.y: %d", i, zone.getOrgPoint_x(i), zone.getOrgPoint_y(i)));
    }
      /* Reset graphics state. */
    exec.graphics_state = ((TTSizeRec)size).getGraphics_state();
      /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
      /*      completely refer to the (already) hinted subglyphs.     */
    if (is_composite) {

Changes to afttruetype/TTSizeRec.java.

347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
      }
    } else {
      error = FTError.ErrorTag.ERR_OK;
    }

      /* UNDOCUMENTED!  The MS rasterizer doesn't allow the following */
      /* graphics state variables to be modified by the CVT program.  */
    exec.graphics_state.getDualVector().x = 0x4000;
    exec.graphics_state.getDualVector().y = 0;
    exec.graphics_state.getProjVector().x = 0x4000;
    exec.graphics_state.getProjVector().y = 0x0;
    exec.graphics_state.getFreeVector().x = 0x4000;
    exec.graphics_state.getFreeVector().y = 0x0;
    exec.graphics_state.setRp0(0);
    exec.graphics_state.setRp1(0);
    exec.graphics_state.setRp2(0);
    exec.graphics_state.setGep0(1);
    exec.graphics_state.setGep1(1);
    exec.graphics_state.setGep2(1);
    exec.graphics_state.setLoop(1);







|
|
|
|
|
|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
      }
    } else {
      error = FTError.ErrorTag.ERR_OK;
    }

      /* UNDOCUMENTED!  The MS rasterizer doesn't allow the following */
      /* graphics state variables to be modified by the CVT program.  */
    exec.graphics_state.getDualVector().setX(0x4000);
    exec.graphics_state.getDualVector().setY(0);
    exec.graphics_state.getProjVector().setX(0x4000);
    exec.graphics_state.getProjVector().setY(0x0);
    exec.graphics_state.getFreeVector().setX(0x4000);
    exec.graphics_state.getFreeVector().setY(0x0);
    exec.graphics_state.setRp0(0);
    exec.graphics_state.setRp1(0);
    exec.graphics_state.setRp2(0);
    exec.graphics_state.setGep0(1);
    exec.graphics_state.setGep1(1);
    exec.graphics_state.setGep2(1);
    exec.graphics_state.setLoop(1);

Changes to aftttinterpreter/TTExecContextRec.java.

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
    for( int i = 0; i < 6; i++) {
//  Debug(0, DebugTag.DBG_INTERP, TAG, String.format("zp1.org: %d x: %d, y: %d\n", i, cur.zp1.org[i].x, cur.zp1.org[i].y));
//  Debug(0, DebugTag.DBG_INTERP, TAG, String.format("zp0.org: %d x: %d, y: %d\n", i, cur.zp0.org[i].x, cur.zp0.org[i].y));
    }
    graphics_state.setGep0(1);
    graphics_state.setGep1(1);
    graphics_state.setGep2(1);
    graphics_state.getProjVector().x = 0x4000;
    graphics_state.getProjVector().y = 0x0000;
    graphics_state.getFreeVector().x = graphics_state.getProjVector().x;
    graphics_state.getFreeVector().y = graphics_state.getProjVector().y;
    graphics_state.getDualVector().x = graphics_state.getProjVector().x;
    graphics_state.getDualVector().y = graphics_state.getProjVector().y;
    graphics_state.setRound_state(TTInterpTags.Round.To_Grid);
    graphics_state.setLoop(1);
    /* some glyphs leave something on the stack. so we clean it */
    /* before a new execution.                                  */
    top = 0;
    callTop = 0;
    return face.Interpreter(this);







|
|
|
|
|
|







352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
    for( int i = 0; i < 6; i++) {
//  Debug(0, DebugTag.DBG_INTERP, TAG, String.format("zp1.org: %d x: %d, y: %d\n", i, cur.zp1.org[i].x, cur.zp1.org[i].y));
//  Debug(0, DebugTag.DBG_INTERP, TAG, String.format("zp0.org: %d x: %d, y: %d\n", i, cur.zp0.org[i].x, cur.zp0.org[i].y));
    }
    graphics_state.setGep0(1);
    graphics_state.setGep1(1);
    graphics_state.setGep2(1);
    graphics_state.getProjVector().setX(0x4000);
    graphics_state.getProjVector().setY(0x0000);
    graphics_state.getFreeVector().setX(graphics_state.getProjVector().getX());
    graphics_state.getFreeVector().setY(graphics_state.getProjVector().getY());
    graphics_state.getDualVector().setX(graphics_state.getProjVector().getX());
    graphics_state.getDualVector().setY(graphics_state.getProjVector().getY());
    graphics_state.setRound_state(TTInterpTags.Round.To_Grid);
    graphics_state.setLoop(1);
    /* some glyphs leave something on the stack. so we clean it */
    /* before a new execution.                                  */
    top = 0;
    callTop = 0;
    return face.Interpreter(this);

Changes to aftttinterpreter/TTGraphicsStateRec.java.

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("...rp0: "+rp0+'\n');
    str.append("...rp1: "+rp1+'\n');
    str.append("...rp2: "+rp2+'\n');
    str.append("...dualVector: x: "+dualVector.x+" y: "+dualVector.y+'\n');
    str.append("...projVector: x: "+projVector.x+" y: "+projVector.y+'\n');
    str.append("...freeVector: x: "+freeVector.x+" y: "+freeVector.y+'\n');
    str.append("...loop: "+loop+'\n');
    str.append("...minimum_distance: "+minimum_distance+'\n');
    str.append("...round_state: "+round_state+'\n');
    str.append("...auto_flip: "+auto_flip+'\n');
    str.append("...control_value_cutin: "+control_value_cutin+'\n');
    str.append("...single_width_cutin: "+single_width_cutin+'\n');
    str.append("...single_width_value: "+single_width_value+'\n');







|
|
|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("...rp0: "+rp0+'\n');
    str.append("...rp1: "+rp1+'\n');
    str.append("...rp2: "+rp2+'\n');
    str.append("...dualVector: x: "+dualVector.getX()+" y: "+dualVector.getY()+'\n');
    str.append("...projVector: x: "+projVector.getX()+" y: "+projVector.getY()+'\n');
    str.append("...freeVector: x: "+freeVector.getX()+" y: "+freeVector.getY()+'\n');
    str.append("...loop: "+loop+'\n');
    str.append("...minimum_distance: "+minimum_distance+'\n');
    str.append("...round_state: "+round_state+'\n');
    str.append("...auto_flip: "+auto_flip+'\n');
    str.append("...control_value_cutin: "+control_value_cutin+'\n');
    str.append("...single_width_cutin: "+single_width_cutin+'\n');
    str.append("...single_width_value: "+single_width_value+'\n');

Changes to aftttinterpreter/TTInstructionFuncGrp0.java.

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
..
93
94
95
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
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return false;
    }
    p1 = cur.zp1.getCurPoint(aIdx2);
    p2 = cur.zp2.getCurPoint(aIdx1);
    A = p1.x - p2.x;
    B = p1.y - p2.y;
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("1: A: %d B: %d", A, B));
      /* If p1 == p2, SPVTL and SFVTL behave the same as */
      /* SPVTCA[X] and SFVTCA[X], respectively.          */
      /*                                                 */
      /* Confirmed by Greg Hitchcock.                    */
    if (A == 0 && B == 0) {
      A = 0x4000;
................................................................................
      C = B;   /* counter clockwise rotation */
      B = A;
      A = -C;
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("2: A: %d B: %d", A, B));
    TTUtil.Normalize(A, B, vec_ref);
    FTVectorRec vec = vec_ref.Get();
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("vec: %d %d", vec.x, vec.y));
    return true;
  }

  /* =====================================================================
   * SPVTL[a]:     Set PVector To Line
   * Opcode range: 0x06-0x07
   * Stack:        uint32 uint32 -->
   * =====================================================================
   */
  public void SPvTL() {
    FTReference<FTVectorRec> ft_unit_ref = new FTReference<FTVectorRec>();

    ft_unit_ref.Set(cur.graphics_state.projVector);
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("SPvTL: %d, %d", cur.stack[cur.stack_idx + 1], cur.stack[cur.stack_idx + 0]));
    if (SxVTL(cur.stack[cur.stack_idx + 1], cur.stack[cur.stack_idx + 0], cur.opcode, ft_unit_ref)) {
      cur.graphics_state.projVector = ft_unit_ref.Get();
      cur.graphics_state.dualVector = ft_unit_ref.Get();
      cur.render_funcs.ComputeFuncs(cur);
    }
  }

................................................................................
  /* =====================================================================
   * GPV[]:        Get Projection Vector
   * Opcode range: 0x0C
   * Stack:        ef2.14 --> ef2.14
   * =====================================================================
   */
  public void GPV() {
    cur.stack[cur.stack_idx + 0] = cur.graphics_state.projVector.x & 0xFFFF;
    cur.stack[cur.stack_idx + 1] = cur.graphics_state.projVector.y & 0xFFFF;
  }

  /* =====================================================================
   * GFV[]:        Get Freedom Vector
   * Opcode range: 0x0D
   * Stack:        ef2.14 --> ef2.14
   * =====================================================================
   */
  public void GFV() {
    cur.stack[cur.stack_idx + 0] = cur.graphics_state.freeVector.x & 0xFFFF;
    cur.stack[cur.stack_idx + 1] = cur.graphics_state.freeVector.y & 0xFFFF;
  }

  /* =====================================================================
   * SFVTPV[]:     Set FVector To PVector
   * Opcode range: 0x0E
   * Stack:        -->
   * =====================================================================
................................................................................
      /* Indeed,                                                           */
      /*       dotproduct   = |da||db|cos(angle)                           */
      /*       discriminant = |da||db|sin(angle)     .                     */
      /* We use these equations to reject grazing intersections by         */
      /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
    if (19 * FTCalc.FT_ABS(discriminant) > FTCalc.FT_ABS(dotproduct)) {
      val = FTCalc.FT_MulDiv(dx, -dby, 0x40) + FTCalc.FT_MulDiv(dy, dbx, 0x40);
      R.x = FTCalc.FT_MulDiv(val, dax, discriminant);
      R.y = FTCalc.FT_MulDiv(val, day, discriminant);
      cur.zp2.setCurPoint_x(point, (cur.zp1.getCurPoint_x(a0) + R.x));
      cur.zp2.setCurPoint_y(point, (cur.zp1.getCurPoint_y(a0) + R.y));
    } else {
        /* else, take the middle of the middles of A and B */
      cur.zp2.setCurPoint_x(point, ((cur.zp1.getCurPoint_x(a0) + cur.zp1.getCurPoint_x(a1) +
          cur.zp0.getCurPoint_x(b0) + cur.zp0.getCurPoint_x(b1)) / 4));
      cur.zp2.setCurPoint_y(point, ((cur.zp1.getCurPoint_y(a0) + cur.zp1.getCurPoint_y(a1) +
          cur.zp0.getCurPoint_y(b0) + cur.zp0.getCurPoint_y(b1)) / 4));
    }
  }

}







|
|







 







|













|







 







|
|









|
|







 







|
|
|
|










74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
..
93
94
95
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
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return false;
    }
    p1 = cur.zp1.getCurPoint(aIdx2);
    p2 = cur.zp2.getCurPoint(aIdx1);
    A = p1.getX() - p2.getX();
    B = p1.getY() - p2.getY();
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("1: A: %d B: %d", A, B));
      /* If p1 == p2, SPVTL and SFVTL behave the same as */
      /* SPVTCA[X] and SFVTCA[X], respectively.          */
      /*                                                 */
      /* Confirmed by Greg Hitchcock.                    */
    if (A == 0 && B == 0) {
      A = 0x4000;
................................................................................
      C = B;   /* counter clockwise rotation */
      B = A;
      A = -C;
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("2: A: %d B: %d", A, B));
    TTUtil.Normalize(A, B, vec_ref);
    FTVectorRec vec = vec_ref.Get();
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("vec: %d %d", vec.getX(), vec.getY()));
    return true;
  }

  /* =====================================================================
   * SPVTL[a]:     Set PVector To Line
   * Opcode range: 0x06-0x07
   * Stack:        uint32 uint32 -->
   * =====================================================================
   */
  public void SPvTL() {
    FTReference<FTVectorRec> ft_unit_ref = new FTReference<FTVectorRec>();

    ft_unit_ref.Set(cur.graphics_state.projVector);
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("SPvTL: %d, %d", cur.stack[cur.stack_idx + 1], cur.stack[cur.stack_idx + 0]));
    if (SxVTL(cur.stack[cur.stack_idx + 1], cur.stack[cur.stack_idx + 0], cur.opcode, ft_unit_ref)) {
      cur.graphics_state.projVector = ft_unit_ref.Get();
      cur.graphics_state.dualVector = ft_unit_ref.Get();
      cur.render_funcs.ComputeFuncs(cur);
    }
  }

................................................................................
  /* =====================================================================
   * GPV[]:        Get Projection Vector
   * Opcode range: 0x0C
   * Stack:        ef2.14 --> ef2.14
   * =====================================================================
   */
  public void GPV() {
    cur.stack[cur.stack_idx] = cur.graphics_state.projVector.getX() & 0xFFFF;
    cur.stack[cur.stack_idx + 1] = cur.graphics_state.projVector.getY() & 0xFFFF;
  }

  /* =====================================================================
   * GFV[]:        Get Freedom Vector
   * Opcode range: 0x0D
   * Stack:        ef2.14 --> ef2.14
   * =====================================================================
   */
  public void GFV() {
    cur.stack[cur.stack_idx] = cur.graphics_state.freeVector.getX() & 0xFFFF;
    cur.stack[cur.stack_idx + 1] = cur.graphics_state.freeVector.getY() & 0xFFFF;
  }

  /* =====================================================================
   * SFVTPV[]:     Set FVector To PVector
   * Opcode range: 0x0E
   * Stack:        -->
   * =====================================================================
................................................................................
      /* Indeed,                                                           */
      /*       dotproduct   = |da||db|cos(angle)                           */
      /*       discriminant = |da||db|sin(angle)     .                     */
      /* We use these equations to reject grazing intersections by         */
      /* thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. */
    if (19 * FTCalc.FT_ABS(discriminant) > FTCalc.FT_ABS(dotproduct)) {
      val = FTCalc.FT_MulDiv(dx, -dby, 0x40) + FTCalc.FT_MulDiv(dy, dbx, 0x40);
      R.setX(FTCalc.FT_MulDiv(val, dax, discriminant));
      R.setY(FTCalc.FT_MulDiv(val, day, discriminant));
      cur.zp2.setCurPoint_x(point, (cur.zp1.getCurPoint_x(a0) + R.getX()));
      cur.zp2.setCurPoint_y(point, (cur.zp1.getCurPoint_y(a0) + R.getY()));
    } else {
        /* else, take the middle of the middles of A and B */
      cur.zp2.setCurPoint_x(point, ((cur.zp1.getCurPoint_x(a0) + cur.zp1.getCurPoint_x(a1) +
          cur.zp0.getCurPoint_x(b0) + cur.zp0.getCurPoint_x(b1)) / 4));
      cur.zp2.setCurPoint_y(point, ((cur.zp1.getCurPoint_y(a0) + cur.zp1.getCurPoint_y(a1) +
          cur.zp0.getCurPoint_y(b0) + cur.zp0.getCurPoint_y(b1)) / 4));
    }
  }

}

Changes to aftttinterpreter/TTInstructionFuncGrp1.java.

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
..
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
   */
  public void SVTCA() {
    int A;
    int B;

    A = (cur.opcode.getVal() & 1) << 14;
    B = A ^ 0x4000;
    cur.graphics_state.freeVector.x = A;
    cur.graphics_state.projVector.x = A;
    cur.graphics_state.dualVector.x = A;
    cur.graphics_state.freeVector.y = B;
    cur.graphics_state.projVector.y = B;
    cur.graphics_state.dualVector.y = B;
    cur.render_funcs.ComputeFuncs(cur);
  }

  /* =====================================================================
   * SPVTCA[a]:    Set PVector to Coordinate Axis
   * Opcode range: 0x02-0x03
   * Stack:        -->
................................................................................
   */
  public void SPVTCA() {
    int A;
    int B;

    A = (cur.opcode.getVal() & 1) << 14;
    B = A ^ 0x4000;
    cur.graphics_state.projVector.x = A;
    cur.graphics_state.dualVector.x = A;
    cur.graphics_state.projVector.y = B;
    cur.graphics_state.dualVector.y = B;
    cur.render_funcs.ComputeFuncs(cur);
  }

  /* =====================================================================
   * SFVTCA[a]:    Set FVector to Coordinate Axis
   * Opcode range: 0x04-0x05
   * Stack:        -->
................................................................................
   */
  public void SFVTCA() {
    int A;
    int B;

    A = (cur.opcode.getVal() & 1) << 14;
    B = A ^ 0x4000;
    cur.graphics_state.freeVector.x = A;
    cur.graphics_state.freeVector.y = B;
    cur.render_funcs.ComputeFuncs(cur);
  }

  /* =====================================================================
   * SRP0[]:       Set Reference Point 0
   * Opcode range: 0x10
   * Stack:        uint32 -->







|
|
|
|
|
|







 







|
|
|
|







 







|
|







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
..
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
   */
  public void SVTCA() {
    int A;
    int B;

    A = (cur.opcode.getVal() & 1) << 14;
    B = A ^ 0x4000;
    cur.graphics_state.freeVector.setX(A);
    cur.graphics_state.projVector.setX(A);
    cur.graphics_state.dualVector.setX(A);
    cur.graphics_state.freeVector.setY(B);
    cur.graphics_state.projVector.setY(B);
    cur.graphics_state.dualVector.setY(B);
    cur.render_funcs.ComputeFuncs(cur);
  }

  /* =====================================================================
   * SPVTCA[a]:    Set PVector to Coordinate Axis
   * Opcode range: 0x02-0x03
   * Stack:        -->
................................................................................
   */
  public void SPVTCA() {
    int A;
    int B;

    A = (cur.opcode.getVal() & 1) << 14;
    B = A ^ 0x4000;
    cur.graphics_state.projVector.setX(A);
    cur.graphics_state.dualVector.setX(A);
    cur.graphics_state.projVector.setY(B);
    cur.graphics_state.dualVector.setY(B);
    cur.render_funcs.ComputeFuncs(cur);
  }

  /* =====================================================================
   * SFVTCA[a]:    Set FVector to Coordinate Axis
   * Opcode range: 0x04-0x05
   * Stack:        -->
................................................................................
   */
  public void SFVTCA() {
    int A;
    int B;

    A = (cur.opcode.getVal() & 1) << 14;
    B = A ^ 0x4000;
    cur.graphics_state.freeVector.setX(A);
    cur.graphics_state.freeVector.setY(B);
    cur.render_funcs.ComputeFuncs(cur);
  }

  /* =====================================================================
   * SRP0[]:       Set Reference Point 0
   * Opcode range: 0x10
   * Stack:        uint32 -->

Changes to aftttinterpreter/TTInstructionFuncGrp2.java.

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
    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.x != 0) {
      mask &= ~Flags.Curve.TOUCH_X.getVal();
    }
    if (cur.graphics_state.freeVector.y != 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







|


|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
    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

Changes to aftttinterpreter/TTInstructionFuncGrp3.java.

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
...
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
623
624
625
626
627
628
629
...
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
663
664
...
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
      int_ref.Set(0);
      return false;
    }
    zone_ref.Set(zp);
    int_ref.Set(p);
    d = cur.funcProject(zp.getCurPoint_x(p) - zp.getOrgPoint_x(p),
        zp.getCurPoint_y(p) - zp.getOrgPoint_y(p));
    x = FTCalc.FT_MulDiv(d, cur.graphics_state.freeVector.x, cur.F_dot_P);
    x_ref.Set(x);
    y = FTCalc.FT_MulDiv(d, cur.graphics_state.freeVector.y, cur.F_dot_P);
    y_ref.Set(y);
    return true;
  }

  /* =====================================================================
   * MoveZp2Point
   * =====================================================================
   */
  private void MoveZp2Point(int point, int dx, int dy, boolean touch) {
    if (cur.graphics_state.freeVector.x != 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.y != 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());
      }
    }
  }

................................................................................
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      cur.graphics_state.loop = 1;
      cur.new_top = cur.stack_idx;
      return;
    }
    dx = TTUtil.TTMulFix14(cur.stack[cur.stack_idx], cur.graphics_state.freeVector.x);
    dy = TTUtil.TTMulFix14(cur.stack[cur.stack_idx], cur.graphics_state.freeVector.y);
    while (cur.graphics_state.loop > 0) {
      cur.stack_idx--;
      point = cur.stack[cur.stack_idx];
      if (TTUtil.BOUNDS(point, cur.zp2.getN_points())) {
        if (cur.pedantic_hinting) {
          cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
          return;
................................................................................
      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.x,orus_base.y));
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("orus2.x: %d, orus2.y: %d", cur.zp0.getOrus()[cur.zp0.getOrus_idx() + 1].x, cur.zp0.getOrus()[cur.zp0.getOrus_idx() + 1].y));
    }
    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())) {
      old_range = 0;
      cur_range = 0;
    } else {
      if (twilight) {
        old_range = cur.funcDualproj(cur.zp1.getOrgPoint_x(cur.graphics_state.rp2) - orus_base.x,
            cur.zp1.getOrgPoint_y(cur.graphics_state.rp2) - orus_base.y);
      } else {
        System.out.println(String.format("x_scale: %d,  y_scale:%d", cur.metrics.getX_scale(), cur.metrics.getY_scale()));
        if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
          Debug(0, DebugTag.DBG_INTERP, TAG, String.format("rp2: %d, zp1.orus.x: %d, x: %d, zp1.orus.y: %d, y: %d", cur.graphics_state.rp2, cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].x, orus_base.x,
              cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].y, orus_base.y));
          old_range = cur.funcDualproj(cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].x - orus_base.x,
              cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].y - orus_base.y);
          Debug(0, DebugTag.DBG_INTERP, TAG, String.format("old_range: %d, rp2.x: %d, rp2.y: %d, orus.x: %d, orus.y: %d", old_range, cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].x, cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].y, orus_base.x, orus_base.y));
        } else {
          FTVectorRec vec = new FTVectorRec();

          vec.x = TTUtil.FTMulFix(cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].x - orus_base.x, cur.metrics.getX_scale());
          vec.y = TTUtil.FTMulFix(cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].y - orus_base.y, cur.metrics.getY_scale());
          old_range = cur.funcDualproj(vec.x, vec.y);
        }
      }
      cur_range = cur.funcProject(cur.zp1.getCurPoint_x(cur.graphics_state.rp2) - cur_base.x,
          cur.zp1.getCurPoint_y(cur.graphics_state.rp2) - cur_base.y);
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("old_range:%d cur_range: %d", old_range, cur_range));
    for (; cur.graphics_state.loop > 0; --cur.graphics_state.loop) {
      int point = cur.stack[--cur.stack_idx];
      int org_dist;
      int cur_dist;
      int new_dist;
................................................................................
        if (cur.pedantic_hinting) {
          cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
          return;
        }
        continue;
      }
      if (twilight) {
        org_dist = cur.funcDualproj(cur.zp2.getOrgPoint_x(point) - orus_base.x,
            cur.zp2.getOrgPoint_y(point) - orus_base.y);
      } else {
        if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
          org_dist = cur.funcDualproj(cur.zp2.getOrus()[cur.zp2.getOrus_idx() + point].x - orus_base.x,
              cur.zp2.getOrus()[cur.zp2.getOrus_idx() + point].y - orus_base.y);
        } else {
          FTVectorRec vec = new FTVectorRec();

          vec.x = TTUtil.FTMulFix(cur.zp2.getOrus()[cur.zp2.getOrus_idx() + point].x - orus_base.x,
              cur.metrics.getX_scale());
          vec.y = TTUtil.FTMulFix(cur.zp2.getOrus()[cur.zp2.getOrus_idx() + point].y - orus_base.y,
              cur.metrics.getY_scale());
          org_dist = cur.funcDualproj(vec.x, vec.y);
        }
      }
      cur_dist = cur.funcProject(cur.zp2.getCurPoint_x(point) - cur_base.x,
          cur.zp2.getCurPoint_y(point) - cur_base.y);
      if (org_dist != 0) {
        if (old_range != 0) {
          new_dist = FTCalc.FT_MulDiv(org_dist, cur_range, old_range);
        } else {
            /* This is the same as what MS does for the invalid case:  */
            /*                                                         */
            /*   delta = (Original_Pt - Original_RP1) -                */
................................................................................
      /*                                                                    */
      /* We implement it with a special sequence for the twilight zone.     */
      /* This is a bad hack, but it seems to work.                          */
      /*                                                                    */
      /* Confirmed by Greg Hitchcock.                                       */
    distance = cur.funcReadCvt(0);
    if (cur.graphics_state.gep0 == 0) {  /* If in twilight zone */
      cur.zp0.setOrgPoint_x(point, (TTUtil.TTMulFix14(distance, cur.graphics_state.freeVector.x)));
      cur.zp0.setOrgPoint_y(point, (TTUtil.TTMulFix14(distance, cur.graphics_state.freeVector.y)));
      cur.zp0.setCurPoint(point, cur.zp0.getOrgPoint(point));
    }
    org_dist = cur.funcProject(cur.zp0.getCurPoint_x(point) - cur.zp0.getCurPoint_x(point),
        cur.zp0.getCurPoint_y(point) - cur.zp0.getCurPoint_y(point));
    if ((cur.opcode.getVal() & 1) != 0) {  /* rounding and control cut-in flag */
      if (FTCalc.FT_ABS(distance - org_dist) > control_value_cutin) {
        distance = org_dist;







|

|









|





|







 







|
|







 







|
|











|
|



|
|
|
|
|



|
|
|


|
|







 







|
|


|
|



|
|
|
|
|


|
|







 







|
|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
...
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
...
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
623
624
625
626
627
628
629
...
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
663
664
...
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
      int_ref.Set(0);
      return false;
    }
    zone_ref.Set(zp);
    int_ref.Set(p);
    d = cur.funcProject(zp.getCurPoint_x(p) - zp.getOrgPoint_x(p),
        zp.getCurPoint_y(p) - zp.getOrgPoint_y(p));
    x = FTCalc.FT_MulDiv(d, cur.graphics_state.freeVector.getX(), cur.F_dot_P);
    x_ref.Set(x);
    y = FTCalc.FT_MulDiv(d, cur.graphics_state.freeVector.getY(), cur.F_dot_P);
    y_ref.Set(y);
    return true;
  }

  /* =====================================================================
   * 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());
      }
    }
  }

................................................................................
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      cur.graphics_state.loop = 1;
      cur.new_top = cur.stack_idx;
      return;
    }
    dx = TTUtil.TTMulFix14(cur.stack[cur.stack_idx], cur.graphics_state.freeVector.getX());
    dy = TTUtil.TTMulFix14(cur.stack[cur.stack_idx], cur.graphics_state.freeVector.getY());
    while (cur.graphics_state.loop > 0) {
      cur.stack_idx--;
      point = cur.stack[cur.stack_idx];
      if (TTUtil.BOUNDS(point, cur.zp2.getN_points())) {
        if (cur.pedantic_hinting) {
          cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
          return;
................................................................................
      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())) {
      old_range = 0;
      cur_range = 0;
    } else {
      if (twilight) {
        old_range = cur.funcDualproj(cur.zp1.getOrgPoint_x(cur.graphics_state.rp2) - orus_base.getX(),
            cur.zp1.getOrgPoint_y(cur.graphics_state.rp2) - orus_base.getY());
      } else {
        System.out.println(String.format("x_scale: %d,  y_scale:%d", cur.metrics.getX_scale(), cur.metrics.getY_scale()));
        if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
          Debug(0, DebugTag.DBG_INTERP, TAG, String.format("rp2: %d, zp1.orus.x: %d, x: %d, zp1.orus.y: %d, y: %d", cur.graphics_state.rp2, cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].getX(), orus_base.getX(),
              cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].getY(), orus_base.getY()));
          old_range = cur.funcDualproj(cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].getX() - orus_base.getX(),
              cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].getY() - orus_base.getY());
          Debug(0, DebugTag.DBG_INTERP, TAG, String.format("old_range: %d, rp2.x: %d, rp2.y: %d, orus.x: %d, orus.y: %d", old_range, cur.zp1.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp2].getX(), cur.zp1.getOrusPoint_y(cur.graphics_state.rp2), orus_base.getX(), orus_base.getY()));
        } else {
          FTVectorRec vec = new FTVectorRec();

          vec.setX(TTUtil.FTMulFix(cur.zp1.getOrusPoint_x(cur.graphics_state.rp2) - orus_base.getX(), cur.metrics.getX_scale()));
          vec.setY(TTUtil.FTMulFix(cur.zp1.getOrusPoint_y(cur.graphics_state.rp2) - orus_base.getY(), cur.metrics.getY_scale()));
          old_range = cur.funcDualproj(vec.getX(), vec.getY());
        }
      }
      cur_range = cur.funcProject(cur.zp1.getCurPoint_x(cur.graphics_state.rp2) - cur_base.getX(),
          cur.zp1.getCurPoint_y(cur.graphics_state.rp2) - cur_base.getY());
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("old_range:%d cur_range: %d", old_range, cur_range));
    for (; cur.graphics_state.loop > 0; --cur.graphics_state.loop) {
      int point = cur.stack[--cur.stack_idx];
      int org_dist;
      int cur_dist;
      int new_dist;
................................................................................
        if (cur.pedantic_hinting) {
          cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
          return;
        }
        continue;
      }
      if (twilight) {
        org_dist = cur.funcDualproj(cur.zp2.getOrgPoint_x(point) - orus_base.getX(),
            cur.zp2.getOrgPoint_y(point) - orus_base.getY());
      } else {
        if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
          org_dist = cur.funcDualproj(cur.zp2.getOrusPoint_x(point) - orus_base.getX(),
              cur.zp2.getOrusPoint_y(point) - orus_base.getY());
        } else {
          FTVectorRec vec = new FTVectorRec();

          vec.setX(TTUtil.FTMulFix(cur.zp2.getOrusPoint_x(point) - orus_base.getX(),
              cur.metrics.getX_scale()));
          vec.setY(TTUtil.FTMulFix(cur.zp2.getOrusPoint_y(point) - orus_base.getY(),
              cur.metrics.getY_scale()));
          org_dist = cur.funcDualproj(vec.getX(), vec.getY());
        }
      }
      cur_dist = cur.funcProject(cur.zp2.getCurPoint_x(point) - cur_base.getX(),
          cur.zp2.getCurPoint_y(point) - cur_base.getY());
      if (org_dist != 0) {
        if (old_range != 0) {
          new_dist = FTCalc.FT_MulDiv(org_dist, cur_range, old_range);
        } else {
            /* This is the same as what MS does for the invalid case:  */
            /*                                                         */
            /*   delta = (Original_Pt - Original_RP1) -                */
................................................................................
      /*                                                                    */
      /* We implement it with a special sequence for the twilight zone.     */
      /* This is a bad hack, but it seems to work.                          */
      /*                                                                    */
      /* Confirmed by Greg Hitchcock.                                       */
    distance = cur.funcReadCvt(0);
    if (cur.graphics_state.gep0 == 0) {  /* If in twilight zone */
      cur.zp0.setOrgPoint_x(point, (TTUtil.TTMulFix14(distance, cur.graphics_state.freeVector.getX())));
      cur.zp0.setOrgPoint_y(point, (TTUtil.TTMulFix14(distance, cur.graphics_state.freeVector.getY())));
      cur.zp0.setCurPoint(point, cur.zp0.getOrgPoint(point));
    }
    org_dist = cur.funcProject(cur.zp0.getCurPoint_x(point) - cur.zp0.getCurPoint_x(point),
        cur.zp0.getCurPoint_y(point) - cur.zp0.getCurPoint_y(point));
    if ((cur.opcode.getVal() & 1) != 0) {  /* rounding and control cut-in flag */
      if (FTCalc.FT_ABS(distance - org_dist) > control_value_cutin) {
        distance = org_dist;

Changes to aftttinterpreter/TTInstructionFuncGrp4.java.

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
...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
   * <Return>
   *    The aspect ratio in 16.16 format, always <= 1.0 .
   *
   * ====================================================================
   */
  protected static int CurrentRatio(TTExecContextRec cur) {
    if (cur.tt_metrics.getRatio() == 0) {
      if (cur.graphics_state.projVector.y == 0) {
        cur.tt_metrics.setRatio(cur.tt_metrics.getX_ratio());
      } else {
        if (cur.graphics_state.projVector.x == 0) {
          cur.tt_metrics.setRatio(cur.tt_metrics.getY_ratio());
        } else {
          int x;
          int y;

          x = TTUtil.TTMulFix14(cur.tt_metrics.getX_ratio(), cur.graphics_state.projVector.x << 2);
          y = TTUtil.TTMulFix14(cur.tt_metrics.getY_ratio(), cur.graphics_state.projVector.y << 2);
          cur.tt_metrics.setRatio(FTCalc.FTHypot(x, y));
        }
      }
    }
    return cur.tt_metrics.getRatio();
  }

................................................................................
    if (TTUtil.BOUNDSL(point_idx, cur.zp2.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      result = 0;
    } else {
      if ((cur.opcode.getVal() & 1) != 0) {
        result = cur.funcDualproj(cur.zp2.getOrgPoint(point_idx).x, cur.zp2.getOrgPoint(point_idx).y);
      } else {
        result = cur.funcProject(cur.zp2.getCurPoint(point_idx).x, cur.zp2.getCurPoint(point_idx).y);
      }
    }
    cur.stack[cur.stack_idx] = result;
  }

  /* =====================================================================
   * SCFS[]:       Set Coordinate From Stack
................................................................................
    point_idx = cur.stack[cur.stack_idx];
    if (TTUtil.BOUNDS(point_idx, cur.zp2.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    result = cur.funcProject(cur.zp2.getCurPoint(point_idx).x, cur.zp2.getCurPoint(point_idx).y);
    cur.funcMove(cur.zp2, point_idx, (cur.stack[cur.stack_idx + 1] - result));
      /* UNDOCUMENTED!  The MS rasterizer does that with */
      /* twilight points (confirmed by Greg Hitchcock)   */
    if (cur.graphics_state.gep2 == 0) {
      cur.zp2.setOrgPoint(point_idx, cur.zp2.getCurPoint(point_idx));
    }
  }
................................................................................
    if (TTUtil.BOUNDS(point1_idx, cur.zp0.getN_points()) || TTUtil.BOUNDS(point2_idx, cur.zp1.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      result = 0;
    } else {
      if ((cur.opcode.getVal() & 1) != 0) {
        result = cur.funcProject(cur.zp0.getCurPoint(point1_idx).x - cur.zp1.getCurPoint(point2_idx).x,
            cur.zp0.getCurPoint(point1_idx).y - cur.zp1.getCurPoint(point2_idx).y);
      } else {
          /* XXX: UNDOCUMENTED: twilight zone special case */
        if (cur.graphics_state.gep0 == 0 || cur.graphics_state.gep1 == 0) {
          FTVectorRec vec1 = cur.zp0.getOrgPoint(point1_idx);
          FTVectorRec vec2 = cur.zp1.getOrgPoint(point2_idx);

          result = cur.render_funcs.curr_project_func.dualproject(vec1.x, vec2.y);
        } else {
          FTVectorRec vec1 = cur.zp0.getOrusPoint(point1_idx);
          FTVectorRec vec2 = cur.zp1.getOrusPoint(point2_idx);

          if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
              /* this should be faster */
            result = cur.render_funcs.curr_project_func.dualproject(vec1.x - vec2.x, vec1.y - vec2.y);
            result = TTUtil.FTMulFix(result, cur.metrics.getX_scale());
          } else {
            FTVectorRec vec = new FTVectorRec();

            vec.x = TTUtil.FTMulFix(vec1.x - vec2.x, cur.metrics.getX_scale());
            vec.y = TTUtil.FTMulFix(vec1.y - vec2.y, cur.metrics.getY_scale());
            result = cur.render_funcs.curr_project_func.dualproject(vec.x, vec.y);
          }
        }
      }
    }
    cur.stack[cur.stack_idx] = result;
  }








|


|





|
|







 







|

|







 







|







 







|
|






|






|




|
|
|







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
...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
...
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
   * <Return>
   *    The aspect ratio in 16.16 format, always <= 1.0 .
   *
   * ====================================================================
   */
  protected static int CurrentRatio(TTExecContextRec cur) {
    if (cur.tt_metrics.getRatio() == 0) {
      if (cur.graphics_state.projVector.getY() == 0) {
        cur.tt_metrics.setRatio(cur.tt_metrics.getX_ratio());
      } else {
        if (cur.graphics_state.projVector.getX() == 0) {
          cur.tt_metrics.setRatio(cur.tt_metrics.getY_ratio());
        } else {
          int x;
          int y;

          x = TTUtil.TTMulFix14(cur.tt_metrics.getX_ratio(), cur.graphics_state.projVector.getX() << 2);
          y = TTUtil.TTMulFix14(cur.tt_metrics.getY_ratio(), cur.graphics_state.projVector.getY() << 2);
          cur.tt_metrics.setRatio(FTCalc.FTHypot(x, y));
        }
      }
    }
    return cur.tt_metrics.getRatio();
  }

................................................................................
    if (TTUtil.BOUNDSL(point_idx, cur.zp2.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      result = 0;
    } else {
      if ((cur.opcode.getVal() & 1) != 0) {
        result = cur.funcDualproj(cur.zp2.getOrgPoint_x(point_idx), cur.zp2.getOrgPoint_y(point_idx));
      } else {
        result = cur.funcProject(cur.zp2.getCurPoint_x(point_idx), cur.zp2.getCurPoint_y(point_idx));
      }
    }
    cur.stack[cur.stack_idx] = result;
  }

  /* =====================================================================
   * SCFS[]:       Set Coordinate From Stack
................................................................................
    point_idx = cur.stack[cur.stack_idx];
    if (TTUtil.BOUNDS(point_idx, cur.zp2.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      return;
    }
    result = cur.funcProject(cur.zp2.getCurPoint_x(point_idx), cur.zp2.getCurPoint_y(point_idx));
    cur.funcMove(cur.zp2, point_idx, (cur.stack[cur.stack_idx + 1] - result));
      /* UNDOCUMENTED!  The MS rasterizer does that with */
      /* twilight points (confirmed by Greg Hitchcock)   */
    if (cur.graphics_state.gep2 == 0) {
      cur.zp2.setOrgPoint(point_idx, cur.zp2.getCurPoint(point_idx));
    }
  }
................................................................................
    if (TTUtil.BOUNDS(point1_idx, cur.zp0.getN_points()) || TTUtil.BOUNDS(point2_idx, cur.zp1.getN_points())) {
      if (cur.pedantic_hinting) {
        cur.error = FTError.ErrorTag.INTERP_INVALID_REFERENCE;
      }
      result = 0;
    } else {
      if ((cur.opcode.getVal() & 1) != 0) {
        result = cur.funcProject(cur.zp0.getCurPoint_x(point1_idx) - cur.zp1.getCurPoint_x(point2_idx),
            cur.zp0.getCurPoint_y(point1_idx) - cur.zp1.getCurPoint_y(point2_idx));
      } else {
          /* XXX: UNDOCUMENTED: twilight zone special case */
        if (cur.graphics_state.gep0 == 0 || cur.graphics_state.gep1 == 0) {
          FTVectorRec vec1 = cur.zp0.getOrgPoint(point1_idx);
          FTVectorRec vec2 = cur.zp1.getOrgPoint(point2_idx);

          result = cur.render_funcs.curr_project_func.dualproject(vec1.getX(), vec2.getY());
        } else {
          FTVectorRec vec1 = cur.zp0.getOrusPoint(point1_idx);
          FTVectorRec vec2 = cur.zp1.getOrusPoint(point2_idx);

          if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
              /* this should be faster */
            result = cur.render_funcs.curr_project_func.dualproject(vec1.getX() - vec2.getX(), vec1.getY() - vec2.getY());
            result = TTUtil.FTMulFix(result, cur.metrics.getX_scale());
          } else {
            FTVectorRec vec = new FTVectorRec();

            vec.setX(TTUtil.FTMulFix(vec1.getX() - vec2.getX(), cur.metrics.getX_scale()));
            vec.setY(TTUtil.FTMulFix(vec1.getY() - vec2.getY(), cur.metrics.getY_scale()));
            result = cur.render_funcs.curr_project_func.dualproject(vec.getX(), vec.getY());
          }
        }
      }
    }
    cur.stack[cur.stack_idx] = result;
  }

Changes to aftttinterpreter/TTInstructionFuncGrp8.java.

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
      }
      return;
    }
    {
      FTVectorRec v1 = cur.zp1.getOrgPoint(p2);
      FTVectorRec v2 = cur.zp2.getOrgPoint(p1);

      A = v1.x - v2.x;
      B = v1.y - v2.y;
        /* If v1 == v2, SDPVTL behaves the same as */
        /* SVTCA[X], respectively.                 */
        /*                                         */
        /* Confirmed by Greg Hitchcock.            */
      if (A == 0 && B == 0) {
        A = 0x4000;
        aOpc = TTOpCode.OpCode.SVTCA_y;
................................................................................
    dualVec_ref.Set(cur.graphics_state.dualVector);
    TTUtil.Normalize(A, B, dualVec_ref);
    cur.graphics_state.dualVector = dualVec_ref.Get();
    {
      FTVectorRec v1 = cur.zp1.getCurPoint(p2);
      FTVectorRec v2 = cur.zp2.getCurPoint(p1);

      A = v1.x - v2.x;
      B = v1.y - v2.y;
      if (A == 0 && B == 0) {
        A = 0x4000;
        aOpc = TTOpCode.OpCode.SVTCA_y;
      }
    }
    if ((aOpc.getVal() & 1) != 0) {
      C = B;   /* counter clockwise rotation */







|
|







 







|
|







204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
      }
      return;
    }
    {
      FTVectorRec v1 = cur.zp1.getOrgPoint(p2);
      FTVectorRec v2 = cur.zp2.getOrgPoint(p1);

      A = v1.getX() - v2.getX();
      B = v1.getY() - v2.getY();
        /* If v1 == v2, SDPVTL behaves the same as */
        /* SVTCA[X], respectively.                 */
        /*                                         */
        /* Confirmed by Greg Hitchcock.            */
      if (A == 0 && B == 0) {
        A = 0x4000;
        aOpc = TTOpCode.OpCode.SVTCA_y;
................................................................................
    dualVec_ref.Set(cur.graphics_state.dualVector);
    TTUtil.Normalize(A, B, dualVec_ref);
    cur.graphics_state.dualVector = dualVec_ref.Get();
    {
      FTVectorRec v1 = cur.zp1.getCurPoint(p2);
      FTVectorRec v2 = cur.zp2.getCurPoint(p1);

      A = v1.getX() - v2.getX();
      B = v1.getY() - v2.getY();
      if (A == 0 && B == 0) {
        A = 0x4000;
        aOpc = TTOpCode.OpCode.SVTCA_y;
      }
    }
    if ((aOpc.getVal() & 1) != 0) {
      C = B;   /* counter clockwise rotation */

Changes to aftttinterpreter/TTInstructionFuncGrp9.java.

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
        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.x)));
      cur.zp1.setOrgPoint_y(point, (cur.zp0.getOrgPoint_y(cur.graphics_state.rp0) + TTUtil.TTMulFix14(cvt_dist, cur.graphics_state.freeVector.y)));
      cur.zp1.setCurPoint(point, cur.zp1.getOrgPoint(point));
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("dualproj: point: %d, GS.rp0: %d, zp1.org[point].x: %d, zp1.org[point].y: %d, zp0.org[GS.rp0].x: %d, zp0.org[GS.rp0].y: %d", point, cur.graphics_state.rp0, cur.zp1.getOrgPoint_x(point), cur.zp1.getOrgPoint_y(point), cur.zp0.getOrgPoint_x(cur.graphics_state.rp0), cur.zp0.getOrgPoint_y(cur.graphics_state.rp0)));
    org_dist = cur.funcDualproj(cur.zp1.getOrgPoint_x(point) - cur.zp0.getOrgPoint_x(cur.graphics_state.rp0),
        cur.zp1.getOrgPoint_y(point) - cur.zp0.getOrgPoint_y(cur.graphics_state.rp0));
    cur_dist = cur.funcProject(cur.zp1.getCurPoint_x(point) - cur.zp0.getCurPoint_x(cur.graphics_state.rp0),
        cur.zp1.getCurPoint_y(point) - cur.zp0.getCurPoint_y(cur.graphics_state.rp0));
................................................................................
      /*      twilight zone?                                  */
      /* XXX: UNDOCUMENTED: twilight zone special case */
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("cur.GS.gep0: %d, cur.GS.gep1: %d\n", cur.graphics_state.gep0, cur.graphics_state.gep1));
    if (cur.graphics_state.gep0 == 0 || cur.graphics_state.gep1 == 0) {
      FTVectorRec vec1 = cur.zp1.getOrgPoint(point);
      FTVectorRec vec2 = cur.zp0.getOrgPoint(cur.graphics_state.rp0);

      org_dist = cur.funcDualproj(vec1.x - vec2.x, vec1.y - vec2.y);
    } else {
      FTVectorRec vec1 = cur.zp1.getOrus()[cur.zp1.getOrus_idx() + point];
      FTVectorRec vec2 = cur.zp0.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp0];

      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("vec1: %d %d, vec2: %d %d\n", vec1.x, vec1.y, vec2.x, vec2.y));
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("x_scale: %d y_scale: %d", cur.metrics.getX_scale(), cur.metrics.getY_scale()));
      if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
          /* this should be faster */
        org_dist = cur.render_funcs.curr_project_func.dualproject(vec1.x - vec2.x, vec1.y - vec2.y);
        Debug(0, DebugTag.DBG_INTERP, TAG, String.format("d1: %d", org_dist));
        org_dist = TTUtil.FTMulFix(org_dist, cur.metrics.getX_scale());
        Debug(0, DebugTag.DBG_INTERP, TAG, String.format("d2: %d", org_dist));
      } else {
        FTVectorRec vec = new FTVectorRec();

        vec.x = TTUtil.FTMulFix(vec1.x - vec2.x, cur.metrics.getX_scale());
        vec.y = TTUtil.FTMulFix(vec1.y - vec2.y, cur.metrics.getY_scale());
        org_dist = cur.render_funcs.curr_project_func.dualproject(vec.x, vec.y);
      }
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, "org_dist1: "+org_dist);
      /* single width cut-in test */
    if (FTCalc.FT_ABS(org_dist - cur.graphics_state.single_width_value) < cur.graphics_state.single_width_cutin) {
      if (org_dist >= 0) {
        org_dist = cur.graphics_state.single_width_value;







|
|







 







|




|



|






|
|
|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
        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));
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("dualproj: point: %d, GS.rp0: %d, zp1.org[point].x: %d, zp1.org[point].y: %d, zp0.org[GS.rp0].x: %d, zp0.org[GS.rp0].y: %d", point, cur.graphics_state.rp0, cur.zp1.getOrgPoint_x(point), cur.zp1.getOrgPoint_y(point), cur.zp0.getOrgPoint_x(cur.graphics_state.rp0), cur.zp0.getOrgPoint_y(cur.graphics_state.rp0)));
    org_dist = cur.funcDualproj(cur.zp1.getOrgPoint_x(point) - cur.zp0.getOrgPoint_x(cur.graphics_state.rp0),
        cur.zp1.getOrgPoint_y(point) - cur.zp0.getOrgPoint_y(cur.graphics_state.rp0));
    cur_dist = cur.funcProject(cur.zp1.getCurPoint_x(point) - cur.zp0.getCurPoint_x(cur.graphics_state.rp0),
        cur.zp1.getCurPoint_y(point) - cur.zp0.getCurPoint_y(cur.graphics_state.rp0));
................................................................................
      /*      twilight zone?                                  */
      /* XXX: UNDOCUMENTED: twilight zone special case */
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("cur.GS.gep0: %d, cur.GS.gep1: %d\n", cur.graphics_state.gep0, cur.graphics_state.gep1));
    if (cur.graphics_state.gep0 == 0 || cur.graphics_state.gep1 == 0) {
      FTVectorRec vec1 = cur.zp1.getOrgPoint(point);
      FTVectorRec vec2 = cur.zp0.getOrgPoint(cur.graphics_state.rp0);

      org_dist = cur.funcDualproj(vec1.getX() - vec2.getX(), vec1.getY() - vec2.getY());
    } else {
      FTVectorRec vec1 = cur.zp1.getOrus()[cur.zp1.getOrus_idx() + point];
      FTVectorRec vec2 = cur.zp0.getOrus()[cur.zp1.getOrus_idx() + cur.graphics_state.rp0];

      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("vec1: %d %d, vec2: %d %d\n", vec1.getX(), vec1.getY(), vec2.getX(), vec2.getY()));
      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("x_scale: %d y_scale: %d", cur.metrics.getX_scale(), cur.metrics.getY_scale()));
      if (cur.metrics.getX_scale() == cur.metrics.getY_scale()) {
          /* this should be faster */
        org_dist = cur.render_funcs.curr_project_func.dualproject(vec1.getX() - vec2.getX(), vec1.getY() - vec2.getY());
        Debug(0, DebugTag.DBG_INTERP, TAG, String.format("d1: %d", org_dist));
        org_dist = TTUtil.FTMulFix(org_dist, cur.metrics.getX_scale());
        Debug(0, DebugTag.DBG_INTERP, TAG, String.format("d2: %d", org_dist));
      } else {
        FTVectorRec vec = new FTVectorRec();

        vec.setX(TTUtil.FTMulFix(vec1.getX() - vec2.getX(), cur.metrics.getX_scale()));
        vec.setY(TTUtil.FTMulFix(vec1.getY() - vec2.getY(), cur.metrics.getY_scale()));
        org_dist = cur.render_funcs.curr_project_func.dualproject(vec.getX(), vec.getY());
      }
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, "org_dist1: "+org_dist);
      /* single width cut-in test */
    if (FTCalc.FT_ABS(org_dist - cur.graphics_state.single_width_value) < cur.graphics_state.single_width_cutin) {
      if (org_dist >= 0) {
        org_dist = cur.graphics_state.single_width_value;

Changes to aftttinterpreter/TTMoveFunc.java.

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
   * =====================================================================
   */
  /* ==================== move ===================================== */
  @Override
  public void move(TTGlyphZoneRec zone, int point, int distance) {
    int v;
    Debug(0, DebugTag.DBG_INTERP, TAG, "DirectMove");
    v = cur.graphics_state.freeVector.x;
    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.y;
    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());
    }
  }

  /* =====================================================================







|




|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
   * =====================================================================
   */
  /* ==================== move ===================================== */
  @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());
    }
  }

  /* =====================================================================

Changes to aftttinterpreter/TTProjectFunc.java.

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
   *
   * =====================================================================
   */
  /* ==================== project ===================================== */
  @Override
  public int project(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, "Project");
    return TTDotFix14(dx, dy, TTRenderFunc.cur.graphics_state.projVector.x, TTRenderFunc.cur.graphics_state.projVector.y);
  }

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

}







|










64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
   *
   * =====================================================================
   */
  /* ==================== project ===================================== */
  @Override
  public int project(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, "Project");
    return TTDotFix14(dx, dy, TTRenderFunc.cur.graphics_state.projVector.getX(), TTRenderFunc.cur.graphics_state.projVector.getY());
  }

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

}

Changes to aftttinterpreter/TTProjectFuncBase.java.

113
114
115
116
117
118
119
120
121
122
123
   *    The distance in F26dot6 format.
   *
   * =====================================================================
   */
  /* ==================== dualproject ===================================== */
  public int dualproject(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, "DualProject");
    return TTDotFix14(dx, dy, TTRenderFunc.cur.graphics_state.getDualVector().x, TTRenderFunc.cur.graphics_state.getDualVector().y);
  }

}







|



113
114
115
116
117
118
119
120
121
122
123
   *    The distance in F26dot6 format.
   *
   * =====================================================================
   */
  /* ==================== dualproject ===================================== */
  public int dualproject(int dx, int dy) {
    Debug(0, DebugTag.DBG_INTERP, TAG, "DualProject");
    return TTDotFix14(dx, dy, TTRenderFunc.cur.graphics_state.getDualVector().getX(), TTRenderFunc.cur.graphics_state.getDualVector().getY());
  }

}

Changes to aftttinterpreter/TTRenderFunc.java.

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
   *    Computes the projection and movement function pointers according
   *    to the current graphics state.
   *
   * =====================================================================
   */
  public void ComputeFuncs(TTExecContextRec exec) {
    cur = exec;
    if (exec.graphics_state.getFreeVector().x == 0x4000) {
      exec.F_dot_P = exec.graphics_state.getProjVector().x;
    } else {
      if (exec.graphics_state.getFreeVector().y == 0x4000) {
        exec.F_dot_P = exec.graphics_state.getProjVector().y;
      } else {
        exec.F_dot_P = (exec.graphics_state.getProjVector().x * exec.graphics_state.getFreeVector().x +
            exec.graphics_state.getProjVector().y * exec.graphics_state.getFreeVector().y) >> 14;
      }
    }
    if (exec.graphics_state.getProjVector().x == 0x4000) {
      curr_project_func = project_x;
    } else {
      if (exec.graphics_state.getProjVector().y == 0x4000) {
        curr_project_func = project_y;
      } else {
        curr_project_func = project;
      }
    }
    curr_move_func = move;
    if (exec.F_dot_P == 0x4000) {
      if (exec.graphics_state.getFreeVector().x == 0x4000) {
        curr_move_func = move_x;
      } else {
        if (exec.graphics_state.getFreeVector().y == 0x4000) {
          curr_move_func = move_y;
        }
      }
    }
      /* at small sizes, F_dot_P can become too small, resulting   */
      /* in overflows and `spikes' in a number of glyphs like `w'. */
    if (FTCalc.FT_ABS(exec.F_dot_P) < 0x400L) {







|
|

|
|

|
|


|


|







|


|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
   *    Computes the projection and movement function pointers according
   *    to the current graphics state.
   *
   * =====================================================================
   */
  public void ComputeFuncs(TTExecContextRec exec) {
    cur = exec;
    if (exec.graphics_state.getFreeVector().getX() == 0x4000) {
      exec.F_dot_P = exec.graphics_state.getProjVector().getX();
    } else {
      if (exec.graphics_state.getFreeVector().getY() == 0x4000) {
        exec.F_dot_P = exec.graphics_state.getProjVector().getY();
      } else {
        exec.F_dot_P = (exec.graphics_state.getProjVector().getX() * exec.graphics_state.getFreeVector().getX() +
            exec.graphics_state.getProjVector().getY() * exec.graphics_state.getFreeVector().getY()) >> 14;
      }
    }
    if (exec.graphics_state.getProjVector().getX() == 0x4000) {
      curr_project_func = project_x;
    } else {
      if (exec.graphics_state.getProjVector().getY() == 0x4000) {
        curr_project_func = project_y;
      } else {
        curr_project_func = project;
      }
    }
    curr_move_func = move;
    if (exec.F_dot_P == 0x4000) {
      if (exec.graphics_state.getFreeVector().getX() == 0x4000) {
        curr_move_func = move_x;
      } else {
        if (exec.graphics_state.getFreeVector().getY() == 0x4000) {
          curr_move_func = move_y;
        }
      }
    }
      /* at small sizes, F_dot_P can become too small, resulting   */
      /* in overflows and `spikes' in a number of glyphs like `w'. */
    if (FTCalc.FT_ABS(exec.F_dot_P) < 0x400L) {

Changes to aftutil/FTCalc.java.

216
217
218
219
220
221
222
223
224
225
226
227
228
      }
      return shift;
    }

    /* ==================== FTHypot ===================================== */
    public static int FTHypot(int x, int y) {
      FTVectorRec v = new FTVectorRec();
      v.x = x;
      v.y = y;
      return FTTrigonometric.FTVectorLength(v);
    }

}







|
|




216
217
218
219
220
221
222
223
224
225
226
227
228
      }
      return shift;
    }

    /* ==================== FTHypot ===================================== */
    public static int FTHypot(int x, int y) {
      FTVectorRec v = new FTVectorRec();
      v.setX(x);
      v.setY(y);
      return FTTrigonometric.FTVectorLength(v);
    }

}

Changes to aftutil/FTMatrixRec.java.

32
33
34
35
36
37
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
65
66
67




68
69
70



71





































  /*    yx :: Matrix coefficient.                                          */
  /*                                                                       */
  /*    yy :: Matrix coefficient.                                          */
  /*                                                                       */
  /* ===================================================================== */

public class FTMatrixRec extends Object {
    private static int oid = 0;

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

    public int xx = 0;
    public int xy = 0;
    public int yx = 0;
    public int yy = 0;

    /* ==================== FTMatricRec ================================== */
    public FTMatrixRec() {
      oid++;
      id = oid;
    }
    
    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
    /* ==================== toString ===================================== */
    public String toString() {
      return mySelf()+"!";
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");




      return str.toString();
    }
 



}












































|

|
|

|
|
|
|

|
|
|
|
|

|
|



|
|



|
|
|
>
>
>
>
|
|
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
32
33
34
35
36
37
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
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
  /*    yx :: Matrix coefficient.                                          */
  /*                                                                       */
  /*    yy :: Matrix coefficient.                                          */
  /*                                                                       */
  /* ===================================================================== */

public class FTMatrixRec extends Object {
  private static int oid = 0;

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

  private int xx = 0;
  private int xy = 0;
  private int yx = 0;
  private int yy = 0;

  /* ==================== FTMatricRec ================================== */
  public FTMatrixRec() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
  /* ==================== toString ===================================== */
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("...xx: "+xx+'\n');
    str.append("...xy: "+xy+'\n');
    str.append("...yx: "+yx+'\n');
    str.append("...yy: "+yy+'\n');
    return str.toString();
  }

  /* ==================== getXx ================================== */
  public int getXx() {
    return xx;
  }

  /* ==================== setXx ================================== */
  public void setXx(int xx) {
    this.xx = xx;
  }

  /* ==================== getXy ================================== */
  public int getXy() {
    return xy;
  }

  /* ==================== setXy ================================== */
  public void setXy(int xy) {
    this.xy = xy;
  }

  /* ==================== getYx ================================== */
  public int getYx() {
    return yx;
  }

  /* ==================== setYx ================================== */
  public void setYx(int yx) {
    this.yx = yx;
  }

  /* ==================== getYy ================================== */
  public int getYy() {
    return yy;
  }

  /* ==================== setYy ================================== */
  public void setYy(int yy) {
    this.yy = yy;
  }

}

Name change from aftutil/FTOpenArgs.java to aftutil/FTOpenArgsRec.java.

11
12
13
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
..
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
98
99
...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
 * =====================================================================
 */

package org.apwtcl.apwfreetypelib.aftutil;

import org.apwtcl.apwfreetypelib.aftbase.FTModuleRec;

import java.io.*;

  /* ===================================================================== */
  /*    FTOpenArgs                                                          */

  /*                                                                       */
  /* <Description>                                                         */
  /*    A structure used to indicate how to open a new font file or        */
  /*    stream.  A pointer to such a structure can be used as a parameter  */
  /*    for the functions @FT_Open_Face and @FT_Attach_Stream.             */
  /*                                                                       */
  /* <Fields>                                                              */
................................................................................
  /*                                                                       */
  /*    Ideally, both the `pathname' and `params' fields should be tagged  */
  /*    as `const'; this is missing for API backwards compatibility.  In   */
  /*    other words, applications should treat them as read-only.          */
  /*                                                                       */
  /* ===================================================================== */

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

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

  private int flags = 0;
  private String pathname = null;
  private FTStreamRec stream = null;
  private FTModuleRec driver = null;
  private int num_params = 0;
  private FTParameter[] params = null;

  /* ==================== FTOpenArgs ================================== */
  public FTOpenArgs() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
................................................................................

  /* ==================== setNum_params ================================== */
  public void setNum_params(int num_params) {
    this.num_params = num_params;
  }

  /* ==================== getParams ================================== */
  public FTParameter[] getParams() {
    return params;
  }

  /* ==================== setParams ================================== */
  public void setParams(FTParameter[] params) {
    this.params = params;
  }

}







<
<

<
>







 







|



|






|

|
|







 







|




|




11
12
13
14
15
16
17


18

19
20
21
22
23
24
25
26
..
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
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
 * =====================================================================
 */

package org.apwtcl.apwfreetypelib.aftutil;

import org.apwtcl.apwfreetypelib.aftbase.FTModuleRec;



  /* ===================================================================== */

  /*    FTOpenArgsRec                                                      */
  /*                                                                       */
  /* <Description>                                                         */
  /*    A structure used to indicate how to open a new font file or        */
  /*    stream.  A pointer to such a structure can be used as a parameter  */
  /*    for the functions @FT_Open_Face and @FT_Attach_Stream.             */
  /*                                                                       */
  /* <Fields>                                                              */
................................................................................
  /*                                                                       */
  /*    Ideally, both the `pathname' and `params' fields should be tagged  */
  /*    as `const'; this is missing for API backwards compatibility.  In   */
  /*    other words, applications should treat them as read-only.          */
  /*                                                                       */
  /* ===================================================================== */

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

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

  private int flags = 0;
  private String pathname = null;
  private FTStreamRec stream = null;
  private FTModuleRec driver = null;
  private int num_params = 0;
  private FTParameterRec[] params = null;

  /* ==================== FTOpenArgsRec ================================== */
  public FTOpenArgsRec() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
................................................................................

  /* ==================== setNum_params ================================== */
  public void setNum_params(int num_params) {
    this.num_params = num_params;
  }

  /* ==================== getParams ================================== */
  public FTParameterRec[] getParams() {
    return params;
  }

  /* ==================== setParams ================================== */
  public void setParams(FTParameterRec[] params) {
    this.params = params;
  }

}

Name change from aftutil/FTParameter.java to aftutil/FTParameterRec.java.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
..
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
98
99
100
101
102
103
104
105
106
107
  /*    various FT_PARAM_TAG_XXX flags for more information.               */
  /*                                                                       */
  /*                                                                       */
  /* ===================================================================== */

import android.util.SparseArray;

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

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

  public enum ParamTag {
    FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY(TTUtil.TagToInt("igpf"), "FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY"),
    FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY(TTUtil.TagToInt("igps"), "FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY"),
    FT_PARAM_TAG_INCREMENTAL(TTUtil.TagToInt("incr"), "FT_PARAM_TAG_INCREMENTAL"),
    FT_PARAM_TAG_UNPATENTED_HINTING(TTUtil.TagToInt("unpa"), "FT_PARAM_TAG_UNPATENTED_HINTING");
    private int val;
................................................................................
      this.str = str;
    }
    public int getVal() {
      return val;
    }
  }

    public ParamTag tag;
    public Object[] data;

    /* ==================== FTParameter ================================== */
    public FTParameter() {
      oid++;
      id = oid;
    }
    
    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
    /* ==================== toString ===================================== */
    public String toString() {
      return mySelf()+"!";
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      return str.toString();
    }

  /* ==================== getTag ===================================== */
  public ParamTag getTag() {
    return tag;
  }

  /* ==================== getData ===================================== */
  public Object getData() {
    return data;
  }

}







|
|

|
|







 







|
|

|
|
|
|
|

|
|



|
|



|
|
|
|
|












30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
..
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
98
99
100
101
102
103
104
105
106
107
  /*    various FT_PARAM_TAG_XXX flags for more information.               */
  /*                                                                       */
  /*                                                                       */
  /* ===================================================================== */

import android.util.SparseArray;

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

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

  public enum ParamTag {
    FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY(TTUtil.TagToInt("igpf"), "FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY"),
    FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY(TTUtil.TagToInt("igps"), "FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY"),
    FT_PARAM_TAG_INCREMENTAL(TTUtil.TagToInt("incr"), "FT_PARAM_TAG_INCREMENTAL"),
    FT_PARAM_TAG_UNPATENTED_HINTING(TTUtil.TagToInt("unpa"), "FT_PARAM_TAG_UNPATENTED_HINTING");
    private int val;
................................................................................
      this.str = str;
    }
    public int getVal() {
      return val;
    }
  }

  private ParamTag tag;
  private Object[] data;

  /* ==================== FTParameter ================================== */
  public FTParameterRec() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
  /* ==================== toString ===================================== */
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }

  /* ==================== getTag ===================================== */
  public ParamTag getTag() {
    return tag;
  }

  /* ==================== getData ===================================== */
  public Object getData() {
    return data;
  }

}

Changes to aftutil/FTStreamRec.java.

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    return str.toString();
  }
 
  /* =====================================================================
   * create a new input stream from an FTOpenArgs structure
   * =====================================================================
   */
  public FTError.ErrorTag Open(FTOpenArgs args) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    if (args == null) {
      Debug(0, DebugTag.DBG_INIT, TAG, "Open invalid argument");
      return FTError.ErrorTag.LOAD_INVALID_ARGUMENT;
    }
    if (args.getPathname() == null) {







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
    return str.toString();
  }
 
  /* =====================================================================
   * create a new input stream from an FTOpenArgs structure
   * =====================================================================
   */
  public FTError.ErrorTag Open(FTOpenArgsRec args) {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;

    if (args == null) {
      Debug(0, DebugTag.DBG_INIT, TAG, "Open invalid argument");
      return FTError.ErrorTag.LOAD_INVALID_ARGUMENT;
    }
    if (args.getPathname() == null) {

Changes to aftutil/FTTrigonometric.java.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
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
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
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

  /* ===================================================================== */
  /*    FTTrigonometric                                                          */
  /*                                                                       */
  /* ===================================================================== */

public class FTTrigonometric extends FTDebug {
    private static int oid = 0;
    private static int[] ft_trig_arctan_table = new int[]
        {
          1740967, 919879, 466945, 234379, 117304, 58666, 29335,
          14668, 7334, 3667, 1833, 917, 458, 229, 115,
          57, 29, 14, 7, 4, 2, 1
        };
    private final static int FT_ANGLE_PI = 180 << 16;
    private final static int FT_ANGLE_PI2 = FT_ANGLE_PI / 2;
    private final static int FT_TRIG_SAFE_MSB = 29;
    private final static int FT_TRIG_MAX_ITERS = 23;
    private final static int FT_TRIG_SCALE = 0xDBD95B16;

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

    /* ==================== FTTrigonometric ================================== */
    public FTTrigonometric() {
      oid++;
      id = oid;
    }
    
    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
    /* ==================== toString ===================================== */
    public String toString() {
      return mySelf()+"!";
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");
      return str.toString();
    }
 
    /* ==================== ft_trig_downscale ================================ */
    private static int ft_trig_downscale(int val) {
      int s;
      int v1;
      int v2;
      int k1;
      int k2;
      int hi;
      int lo1;
      int lo2;
      int lo3;

Debug(0, DebugTag.DBG_RENDER, TAG, "ft_trig_downscale");
      s   = val;
      val = FTCalc.FT_ABS(val);
      v1 = (val >> 16);
      v2 = (val & 0xFFFF);
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("ft_trig_downscale: s: 0x%x, val: 0x%x, v1: 0x%x, v2: 0x%x", s, val, v1, v2));
      k1 = FT_TRIG_SCALE >> 16;         /* constant */
      k2 = (FT_TRIG_SCALE & 0xFFFF);   /* constant */
      hi = k1 * v1;
      lo1 = k1 * v2 + k2 * v1;       /* can't overflow */
      lo2 = (k2 * v2) >> 16;
      lo3 = lo1 > lo2 ? lo1 : lo2;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("ft_trig_downscale2: k1: 0x%x, k2: 0x%x, hi: 0x%x, lo1: 0x%x, lo2: 0x%x, lo3: 0x%x", k1, k2, hi, lo1, lo2, lo3));
      lo1 += lo2;
      hi  += lo1 >> 16;
      if (lo1 < lo3) {
        hi += 0x10000L;
      }
      val  = hi;
      return (s >= 0) ? val : -val;
    }

    /* ==================== ft_trig_prenorm ===================================== */
    private static int ft_trig_prenorm(FTReference<FTVectorRec> vec_ref) {
      int x;
      int y;
      FTVectorRec vec = vec_ref.Get();
      int  shift;

      x = vec.x;
      y = vec.y;
      shift = FTCalc.FT_MSB(FTCalc.FT_ABS(x) | FTCalc.FT_ABS(y));
      if (shift <= FT_TRIG_SAFE_MSB) {
        shift  = FT_TRIG_SAFE_MSB - shift;
        vec.x = x << shift;
        vec.y = y << shift;
      } else {
        shift -= FT_TRIG_SAFE_MSB;
        vec.x = x >> shift;
        vec.y = y >> shift;
        shift  = -shift;
      }
      vec_ref.Set( vec);
      return shift;
    }

    /* ==================== ft_trig_pseudo_polarize ========================= */
    private static void ft_trig_pseudo_polarize (FTReference<FTVectorRec> vec_ref) {
      FTVectorRec vec = vec_ref.Get();
      int theta;
      int i;
      int x;
      int y;
      int xtemp;
      int b;
      int arctanIdx;
      int arctan;

      x = vec.x;
      y = vec.y;
      /* Get the vector into [-PI/4,PI/4] sector */
      if (y > x) {
        if (y > -x) {
          theta = FT_ANGLE_PI2;
          xtemp =  y;
          y = -x;
          x =  xtemp;
        } else {
          theta =  y > 0 ? FT_ANGLE_PI : -FT_ANGLE_PI;
          x = -x;
          y = -y;
        }
      } else {
        if (y < -x) {
          theta = -FT_ANGLE_PI2;
          xtemp = -y;
          y =  x;
          x =  xtemp;
        } else {
          theta = 0;
        }
      }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("theta0: 0x%x, x: 5x%x, y: 0x%x", theta, x, y));
      arctanIdx = 0;
      arctan = ft_trig_arctan_table[arctanIdx];
      /* Pseudorotations, with right shifts */
      b = 1;
      for (i = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++) {
        arctan = ft_trig_arctan_table[arctanIdx];
        if (y > 0) {
          xtemp = x + ((y + b) >> i);
          y = y - ((x + b) >> i);
          x = xtemp;
          theta += arctan;
        } else {
          xtemp = x - ((y + b) >> i);
          y = y + ((x + b) >> i);
          x = xtemp;
          theta -= arctan;
        }
        arctanIdx++;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("theta1: 0x%x, x: 5x%x, y: 0x%x", theta, x, y));
      }
      /* round theta */
      if (theta >= 0) {
        theta = FTCalc.FT_PAD_ROUND(theta, 32);
      } else {
        theta = -FTCalc.FT_PAD_ROUND(-theta, 32);
      }
      vec.x = x;
      vec.y = theta;
      vec_ref.Set(vec);
    }

    /* ==================== FTVectorLength ===================================== */
    public static int FTVectorLength(FTVectorRec vec) {
      int shift;
      FTVectorRec v;
      FTReference<FTVectorRec> v_ref = new FTReference<FTVectorRec>();

Debug(0, DebugTag.DBG_RENDER, TAG, "FTVectorLength");
      v = vec;
      /* handle trivial cases */
      if (v.x == 0) {
        return FTCalc.FT_ABS(v.y);
      } else {
        if (v.y == 0) {
          return FTCalc.FT_ABS(v.x);
        }
      }
      /* general case */
      v_ref.Set(v);
      shift = ft_trig_prenorm(v_ref);
      v = v_ref.Get();
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("shift1: %d, x: 0x%x, y: 0x%x", shift, v.x, v.y));
      ft_trig_pseudo_polarize(v_ref);
      v = v_ref.Get();
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("shift2: %d, x: 0x%x, y: 0x%x", shift, v.x, v.y));
      v.x = ft_trig_downscale(v.x);
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("shift3: %d, x: 0x%x, y: 0x%x", shift, v.x, v.y));
      if (shift > 0) {
        return (v.x + (1 << (shift - 1))) >> shift;
      }
      return (v.x << -shift);
    }

}







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

|
|

|
|
|
|
|

|
|
|
|

|
|
|
|

|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|


|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|
|

|
|
|
|
|
|

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

|
|
|
|
|
|
|
|
|
|
|

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

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

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|


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

|
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
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
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
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

  /* ===================================================================== */
  /*    FTTrigonometric                                                          */
  /*                                                                       */
  /* ===================================================================== */

public class FTTrigonometric extends FTDebug {
  private static int oid = 0;
  private static int[] ft_trig_arctan_table = new int[]
      {
        1740967, 919879, 466945, 234379, 117304, 58666, 29335,
        14668, 7334, 3667, 1833, 917, 458, 229, 115,
        57, 29, 14, 7, 4, 2, 1
      };
  private final static int FT_ANGLE_PI = 180 << 16;
  private final static int FT_ANGLE_PI2 = FT_ANGLE_PI / 2;
  private final static int FT_TRIG_SAFE_MSB = 29;
  private final static int FT_TRIG_MAX_ITERS = 23;
  private final static int FT_TRIG_SCALE = 0xDBD95B16;

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

  /* ==================== FTTrigonometric ================================== */
  public FTTrigonometric() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
    return TAG+"!"+id+"!";
  }
        
  /* ==================== toString ===================================== */
  public String toString() {
    return mySelf()+"!";
  }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    return str.toString();
  }
 
  /* ==================== ft_trig_downscale ================================ */
  private static int ft_trig_downscale(int val) {
    int s;
    int v1;
    int v2;
    int k1;
    int k2;
    int hi;
    int lo1;
    int lo2;
    int lo3;

Debug(0, DebugTag.DBG_RENDER, TAG, "ft_trig_downscale");
    s   = val;
    val = FTCalc.FT_ABS(val);
    v1 = (val >> 16);
    v2 = (val & 0xFFFF);
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("ft_trig_downscale: s: 0x%x, val: 0x%x, v1: 0x%x, v2: 0x%x", s, val, v1, v2));
    k1 = FT_TRIG_SCALE >> 16;         /* constant */
    k2 = (FT_TRIG_SCALE & 0xFFFF);   /* constant */
    hi = k1 * v1;
    lo1 = k1 * v2 + k2 * v1;       /* can't overflow */
    lo2 = (k2 * v2) >> 16;
    lo3 = lo1 > lo2 ? lo1 : lo2;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("ft_trig_downscale2: k1: 0x%x, k2: 0x%x, hi: 0x%x, lo1: 0x%x, lo2: 0x%x, lo3: 0x%x", k1, k2, hi, lo1, lo2, lo3));
    lo1 += lo2;
    hi  += lo1 >> 16;
    if (lo1 < lo3) {
      hi += 0x10000L;
    }
    val  = hi;
    return (s >= 0) ? val : -val;
  }

  /* ==================== ft_trig_prenorm ===================================== */
  private static int ft_trig_prenorm(FTReference<FTVectorRec> vec_ref) {
    int x;
    int y;
    FTVectorRec vec = vec_ref.Get();
    int  shift;

    x = vec.getX();
    y = vec.getY();
    shift = FTCalc.FT_MSB(FTCalc.FT_ABS(x) | FTCalc.FT_ABS(y));
    if (shift <= FT_TRIG_SAFE_MSB) {
      shift  = FT_TRIG_SAFE_MSB - shift;
      vec.setX(x << shift);
      vec.setY(y << shift);
    } else {
      shift -= FT_TRIG_SAFE_MSB;
      vec.setX(x >> shift);
      vec.setY(y >> shift);
      shift  = -shift;
    }
    vec_ref.Set( vec);
    return shift;
  }

  /* ==================== ft_trig_pseudo_polarize ========================= */
  private static void ft_trig_pseudo_polarize (FTReference<FTVectorRec> vec_ref) {
    FTVectorRec vec = vec_ref.Get();
    int theta;
    int i;
    int x;
    int y;
    int xtemp;
    int b;
    int arctanIdx;
    int arctan;

    x = vec.getX();
    y = vec.getY();
    /* Get the vector into [-PI/4,PI/4] sector */
    if (y > x) {
      if (y > -x) {
        theta = FT_ANGLE_PI2;
        xtemp =  y;
        y = -x;
        x =  xtemp;
      } else {
        theta =  y > 0 ? FT_ANGLE_PI : -FT_ANGLE_PI;
        x = -x;
        y = -y;
      }
    } else {
      if (y < -x) {
        theta = -FT_ANGLE_PI2;
        xtemp = -y;
        y =  x;
        x =  xtemp;
      } else {
        theta = 0;
      }
    }
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("theta0: 0x%x, x: 5x%x, y: 0x%x", theta, x, y));
    arctanIdx = 0;
    arctan = ft_trig_arctan_table[arctanIdx];
    /* Pseudorotations, with right shifts */
    b = 1;
    for (i = 1; i < FT_TRIG_MAX_ITERS; b <<= 1, i++) {
      arctan = ft_trig_arctan_table[arctanIdx];
      if (y > 0) {
        xtemp = x + ((y + b) >> i);
        y = y - ((x + b) >> i);
        x = xtemp;
        theta += arctan;
      } else {
        xtemp = x - ((y + b) >> i);
        y = y + ((x + b) >> i);
        x = xtemp;
        theta -= arctan;
      }
      arctanIdx++;
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("theta1: 0x%x, x: 5x%x, y: 0x%x", theta, x, y));
    }
    /* round theta */
    if (theta >= 0) {
      theta = FTCalc.FT_PAD_ROUND(theta, 32);
    } else {
      theta = -FTCalc.FT_PAD_ROUND(-theta, 32);
    }
    vec.setX(x);
    vec.setY(theta);
    vec_ref.Set(vec);
  }

  /* ==================== FTVectorLength ===================================== */
  public static int FTVectorLength(FTVectorRec vec) {
    int shift;
    FTVectorRec v;
    FTReference<FTVectorRec> v_ref = new FTReference<FTVectorRec>();

Debug(0, DebugTag.DBG_RENDER, TAG, "FTVectorLength");
    v = vec;
    /* handle trivial cases */
    if (v.getX() == 0) {
      return FTCalc.FT_ABS(v.getY());
    } else {
      if (v.getY() == 0) {
        return FTCalc.FT_ABS(v.getX());
      }
    }
    /* general case */
    v_ref.Set(v);
    shift = ft_trig_prenorm(v_ref);
    v = v_ref.Get();
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("shift1: %d, x: 0x%x, y: 0x%x", shift, v.getX(), v.getY()));
    ft_trig_pseudo_polarize(v_ref);
    v = v_ref.Get();
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("shift2: %d, x: 0x%x, y: 0x%x", shift, v.getX(), v.getY()));
    v.setX(ft_trig_downscale(v.getX()));
Debug(0, DebugTag.DBG_RENDER, TAG, String.format("shift3: %d, x: 0x%x, y: 0x%x", shift, v.getX(), v.getY()));
    if (shift > 0) {
      return (v.getX() + (1 << (shift - 1))) >> shift;
    }
    return (v.getX() << -shift);
  }

}

Changes to aftutil/FTVectorRec.java.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58



59

















  /*                                                                       */
  /* <Fields>                                                              */
  /*    x :: The horizontal coordinate.                                    */
  /*    y :: The vertical coordinate.                                      */
  /* ===================================================================== */

public class FTVectorRec extends Object {
    private static int oid = 0;

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

    public int x = 0;
    public int y = 0;

    /* ==================== FTVectorRec ================================== */
    public FTVectorRec() {
      oid++;
      id = oid;
    }
    
    /* ==================== mySelf ================================== */
    public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
    /* ==================== toString ===================================== */
    public String toString() {
      return mySelf()+"!";
    }

    /* ==================== toDebugString ===================================== */
    public String toDebugString() {
      StringBuffer str = new StringBuffer(mySelf()+"\n");


      return str.toString();
    }
 



}
























|

|
|

|
|

|
|
|
|
|

|
|



|
|



|
|
|
>
>
|
|
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  /*                                                                       */
  /* <Fields>                                                              */
  /*    x :: The horizontal coordinate.                                    */
  /*    y :: The vertical coordinate.                                      */
  /* ===================================================================== */

public class FTVectorRec extends Object {
  private static int oid = 0;

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

  private int x = 0;
  private int y = 0;

  /* ==================== FTVectorRec ================================== */
  public FTVectorRec() {
    oid++;
    id = oid;
  }
    
  /* ==================== mySelf ================================== */
  public String mySelf() {
      return TAG+"!"+id+"!";
    }
        
  /* ==================== toString ===================================== */
  public String toString() {
      return mySelf()+"!";
    }

  /* ==================== toDebugString ===================================== */
  public String toDebugString() {
    StringBuffer str = new StringBuffer(mySelf()+"\n");
    str.append("...x: "+x+'\n');
    str.append("...y: "+y+'\n');
    return str.toString();
  }

  /* ==================== getX ================================== */
  public int getX() {
    return x;
  }

  /* ==================== setX ================================== */
  public void setX(int x) {
    this.x = x;
  }

  /* ==================== getY ================================== */
  public int getY() {
    return y;
  }

  /* ==================== setY ================================== */
  public void setY(int y) {
    this.y = y;
  }

}

Changes to aftutil/TTUtil.java.

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
      Vx *= 0x4000;
      Vy *= 0x4000;
      Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("Normalize2: Vx: %d, vy: %d", Vx, Vy));
    }
    Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("Normalize2: Vx: %d, vy: %d", Vx, Vy));
    W = FTCalc.FTHypot(Vx, Vy);
    Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("W: %d 0x%x",  W, W));
    R.x = FTCalc.FTDivFix(Vx, W << 2);
    R.y = FTCalc.FTDivFix(Vy, W << 2);
    Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("R.x: %d, R.y: %d", R.x, R.y));
    R_ref.Set(R);
    return true;
  }

  /* ==================== FTMulFix ===================================== */
  public static int FTMulFix(int a, int b) {
    int s = 1;







|
|
|







87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
      Vx *= 0x4000;
      Vy *= 0x4000;
      Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("Normalize2: Vx: %d, vy: %d", Vx, Vy));
    }
    Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("Normalize2: Vx: %d, vy: %d", Vx, Vy));
    W = FTCalc.FTHypot(Vx, Vy);
    Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("W: %d 0x%x",  W, W));
    R.setX(FTCalc.FTDivFix(Vx, W << 2));
    R.setY(FTCalc.FTDivFix(Vy, W << 2));
    Debug(0, FTDebug.DebugTag.DBG_INTERP, TAG, String.format("R.x: %d, R.y: %d", R.getX(), R.getY()));
    R_ref.Set(R);
    return true;
  }

  /* ==================== FTMulFix ===================================== */
  public static int FTMulFix(int a, int b) {
    int s = 1;