apwfreetypelib

Check-in [ef8376af8c]
Login

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

Overview
Comment:make glyph flags/tags a Set. fixes.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ef8376af8cff2bf3ee1c6f4638e7489ee2a78bb5
User & Date: arnulf 2015-02-06 21:18:23
Context
2015-02-06
21:44
fixes. check-in: 6a644b50ad user: arnulf tags: trunk
21:18
make glyph flags/tags a Set. fixes. check-in: ef8376af8c user: arnulf tags: trunk
2015-02-01
19:57
fixes and made Set of enums for Curve flags and Load flags. check-in: 4b013f08ed user: arnulf tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to aftbase/Flags.java.

561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576

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

    public static Curve getTableTag(int i) {
      if (tagToCurveMapping == null) {
        initMapping();







|
|







561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576

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

    public static Curve getTableTag(int i) {
      if (tagToCurveMapping == null) {
        initMapping();

Changes to aftdemo/demo1.java.

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101


      FTFaceRequester requester = new FTDemoFaceRequester();
      FTCManagerRec manager = new FTCManagerRec(library, max_faces, max_sizes, requester, font_args);

      FTCGCacheClassRec sbits_cache = new FTCBasicSCacheClass();    /* the glyph small bitmaps cache */
      error = manager.RegisterCache(sbits_cache);
      Debug(0, DebugTag.DBG_INIT, TAG, "sbits_cache: " + sbits_cache.toDebugString());
      if (error != FTError.ErrorTag.ERR_OK) {
        Log.e(TAG, "could not initialize small bitmaps cache");
        return;
      }

      FTCGCacheClassRec image_cache = new FTCBasicICacheClass();    /* the glyph image cache         */
      Debug(0, DebugTag.DBG_INIT, TAG, "image_cache: " + image_cache.toDebugString());
      error = manager.RegisterCache(image_cache);
      if (error != FTError.ErrorTag.ERR_OK) {
        Log.e(TAG, "could not initialize glyph image cache");
        return;
      }

      FTCGCacheClassRec cmap_cache = new FTCCMapCacheClass();     /* the charmap cache             */







|






|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101


      FTFaceRequester requester = new FTDemoFaceRequester();
      FTCManagerRec manager = new FTCManagerRec(library, max_faces, max_sizes, requester, font_args);

      FTCGCacheClassRec sbits_cache = new FTCBasicSCacheClass();    /* the glyph small bitmaps cache */
      error = manager.RegisterCache(sbits_cache);
Debug(0, DebugTag.DBG_INIT, TAG, "sbits_cache: " + sbits_cache.toDebugString());
      if (error != FTError.ErrorTag.ERR_OK) {
        Log.e(TAG, "could not initialize small bitmaps cache");
        return;
      }

      FTCGCacheClassRec image_cache = new FTCBasicICacheClass();    /* the glyph image cache         */
Debug(0, DebugTag.DBG_INIT, TAG, "image_cache: " + image_cache.toDebugString());
      error = manager.RegisterCache(image_cache);
      if (error != FTError.ErrorTag.ERR_OK) {
        Log.e(TAG, "could not initialize glyph image cache");
        return;
      }

      FTCGCacheClassRec cmap_cache = new FTCCMapCacheClass();     /* the charmap cache             */

Changes to afttruetype/TTGlyphLoaderRec.java.

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
      loader.getGlyph().setControl_len(n_ins);
      loader.getGlyph().setControl_data(loader.getExec().glyphIns);
      for (i = 0; i < n_ins; i++) {
        loader.getExec().glyphIns[i] = TTOpCode.OpCode.getTableTag(ttglyph.getInstructions()[i] & 0xFF);
        if (loader.getExec().glyphIns[i] == null) {
          Log.e(TAG, String.format("loader.getExec().glyphIns[%d] is null!", i));
        } else {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("ins: %d 0x%02x: ", i, loader.getExec().glyphIns[i].getVal()) + loader.getExec().glyphIns[i]);
        }
      }
//        FT_MEM_COPY( loader.exec.glyphIns, p, (FT_Long)n_ins );
    }

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

      /* loading the X and y coordinates */







|









|







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
      loader.getGlyph().setControl_len(n_ins);
      loader.getGlyph().setControl_data(loader.getExec().glyphIns);
      for (i = 0; i < n_ins; i++) {
        loader.getExec().glyphIns[i] = TTOpCode.OpCode.getTableTag(ttglyph.getInstructions()[i] & 0xFF);
        if (loader.getExec().glyphIns[i] == null) {
          Log.e(TAG, String.format("loader.getExec().glyphIns[%d] is null!", i));
        } else {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("glyphInstruction: %d 0x%02x: ", i, loader.getExec().glyphIns[i].getVal()) + loader.getExec().glyphIns[i]);
        }
      }
//        FT_MEM_COPY( loader.exec.glyphIns, p, (FT_Long)n_ins );
    }

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

      /* loading the X and y coordinates */

Changes to afttruetype/TTGlyphSimpleRec.java.

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
..
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
...
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
...
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
...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
...
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
import org.apwtcl.apwfreetypelib.aftbase.Flags;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTStreamRec;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;



public class TTGlyphSimpleRec extends TTGlyphRec {
  private static int oid = 0;

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

  private int[] org_contours = null; /* end points of contours */
  private int instructions_length = 0;
  private byte[] instructions = null;
  private byte[] flags = null;
  private int[] x_coordinates = null;
  private int[] y_coordinates = null;

  /* next fields not in the file */
  private int[] contours = null; /* end points of contours */
  private int num_points = 0;
  private FTVectorRec[] points = null;
  private byte[] tags = null;

  /* ==================== TTGlyphSimpleRec ================================== */
  public TTGlyphSimpleRec() {
    oid++;
    id = oid;
  }
    
................................................................................
    int flag_idx;
    int tag_idx;
    int tag_limit;
    int vec_idx;
    int vec_limit;
    int x;
    int y;
    int tag;
    int delta;

    super.Load(stream, ttface, limit);
    /* the call to super.Load() has already positioned us to the correct file offset! */

Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "after glyph_header: glyf_offset: "+glyf_offset+" "+stream.pos());
   limit += glyf_offset;
................................................................................
    prev_contour = org_contours[0];
    if(num_contours > 0) {
      contours[0] = prev_contour;
    }
    if(prev_contour < 0) {
      return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
    }
    contours = new int[num_contours];
    for(contour_idx = 1; contour_idx < contour_limit; contour_idx++) {
      contours[contour_idx] = org_contours[contour_idx];
      if(contours[contour_idx] <= prev_contour) {
        /* unordered contours: this is invalid */
        return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
      }
      prev_contour = contours[contour_idx];
    }
    num_points = 0;
    if(num_contours > 0) {
      num_points = contours[contour_idx - 1] +1;
      if(num_points < 0) {
        return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
      }
    }

    /* note that we will add four phantom points later */
    points = new FTVectorRec[num_points + 4];
................................................................................
    instructions_length = stream.readShort();
    if(instructions_length > ttface.getMax_profile().getMaxSizeOfInstructions()) {
      return FTError.ErrorTag.GLYPH_TOO_MANY_HINTS;
    }
    if(stream.pos() + instructions_length > limit) {
      return FTError.ErrorTag.GLYPH_TOO_MANY_HINTS;
    }
//    if((loader.load_flags & Flags.Load.NO_AUTOHINT.getVal()) == 0) {

      instructions = new byte[instructions_length];
      stream.readByteArray(instructions, instructions_length);
//    }

    /* reading the point tags */
    flag_idx = 0;
    tag_idx = 0;
    tag_limit = num_points;
    flags = new byte[num_points];
    tags = new byte[num_points];
    while(tag_idx < tag_limit) {
      byte ch;
      int count;

      if(stream.pos() + 1 > limit) {
        return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
      }
      ch = (byte)(stream.readByte() & 0xFF);

      flags[flag_idx] = ch;
      tags[tag_idx++] = ch;
      if((ch & TTTags.GlyphFlags.REPEAT.getVal()) != 0) {
        if(stream.pos() + 1 > limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        count = stream.readByte();
        if(flag_idx + count > tag_limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        while(count > 0) {

          tags[tag_idx++] = ch;
          count--;
        }

      }
      flag_idx++;
    }

................................................................................
    points = new FTVectorRec[num_points];
    for(vec_idx = 0; vec_idx < num_points; vec_idx++) {
      points[vec_idx] = new FTVectorRec();
    }
Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "pos before reading x: "+stream.pos());
    /* reading the X coordinates */
    x_coordinates = new int[num_points];
    vec_idx = 0;
    vec_limit = num_points;
    tag_idx = 0;
    x = 0;
    if(stream.pos() > limit) {
      return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
    }
    for(vec_idx = 0; vec_idx < num_points; vec_idx++) {
      delta = 0;
      tag = tags[vec_idx];
      if((tag & TTTags.GlyphFlags.X_SHORT.getVal()) != 0) {
        if(stream.pos() + 1 > limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        delta = stream.readByte() & 0xFF;
        if((tag & TTTags.GlyphFlags.X_SAME.getVal()) == 0) {
          delta = -delta;
        }
      } else {
        if((tag & TTTags.GlyphFlags.X_SAME.getVal()) == 0) {
          if(stream.pos() + 2 > limit) {
            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;
    vec_limit = num_points;
    tag_idx = 0;
    y = 0;
    if(stream.pos() > limit) {
      return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
    }
    for(vec_idx = 0; vec_idx < num_points; vec_idx++) {
      delta = 0;
      tag = tags[vec_idx];
      if((tag & TTTags.GlyphFlags.Y_SHORT.getVal()) != 0) {
        if(stream.pos() + 1 > limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        delta = stream.readByte() & 0xFF;
        if((tag & TTTags.GlyphFlags.Y_SAME.getVal()) == 0) {
          delta = -delta;
        }
      } else {
        if((tag & TTTags.GlyphFlags.Y_SAME.getVal()) == 0) {
          if(stream.pos() + 2 > limit) {
            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;
  }

  /* ==================== getContours ================================== */
  public int[] getContours() {
    return contours;
  }
................................................................................

  /* ==================== setInstructions ================================== */
  public void setInstructions(byte[] instructions) {
    this.instructions = instructions;
  }

  /* ==================== getFlags ================================== */
  public byte[] getFlags() {
    return flags;
  }

  /* ==================== setFlags ================================== */
  public void setFlags(byte[] flags) {
    this.flags = flags;
  }

  /* ==================== getX_coordinates ================================== */
  public int[] getX_coordinates() {
    return x_coordinates;
  }
................................................................................

  /* ==================== setY_coordinates ================================== */
  public void setY_coordinates(int[] y_coordinates) {
    this.y_coordinates = y_coordinates;
  }

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

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

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

  /* ==================== getPoints ================================== */
  public FTVectorRec[] getPoints() {
    return points;
  }







>
>










|







|







 







|







 







<










|







 







|
>








|
|








>
|
|









>
|







 







<
<








|




|



|









|
>





<
<








|




|



|









|
>
>
>
>



>
>
>
>

|







 







|




|







 







|




|




|







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
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
...
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
...
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
...
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
...
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
import org.apwtcl.apwfreetypelib.aftbase.Flags;
import org.apwtcl.apwfreetypelib.aftutil.FTDebug;
import org.apwtcl.apwfreetypelib.aftutil.FTError;
import org.apwtcl.apwfreetypelib.aftutil.FTReference;
import org.apwtcl.apwfreetypelib.aftutil.FTStreamRec;
import org.apwtcl.apwfreetypelib.aftutil.FTTrace;
import org.apwtcl.apwfreetypelib.aftutil.FTVectorRec;

import java.util.Set;

public class TTGlyphSimpleRec extends TTGlyphRec {
  private static int oid = 0;

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

  private int[] org_contours = null; /* end points of contours */
  private int instructions_length = 0;
  private byte[] instructions = null;
  private Set<TTTags.GlyphFlags>[] flags = null;
  private int[] x_coordinates = null;
  private int[] y_coordinates = null;

  /* next fields not in the file */
  private int[] contours = null; /* end points of contours */
  private int num_points = 0;
  private FTVectorRec[] points = null;
  private Set<TTTags.GlyphFlags>[] tags = null;

  /* ==================== TTGlyphSimpleRec ================================== */
  public TTGlyphSimpleRec() {
    oid++;
    id = oid;
  }
    
................................................................................
    int flag_idx;
    int tag_idx;
    int tag_limit;
    int vec_idx;
    int vec_limit;
    int x;
    int y;
    Set<TTTags.GlyphFlags> tag;
    int delta;

    super.Load(stream, ttface, limit);
    /* the call to super.Load() has already positioned us to the correct file offset! */

Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "after glyph_header: glyf_offset: "+glyf_offset+" "+stream.pos());
   limit += glyf_offset;
................................................................................
    prev_contour = org_contours[0];
    if(num_contours > 0) {
      contours[0] = prev_contour;
    }
    if(prev_contour < 0) {
      return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
    }

    for(contour_idx = 1; contour_idx < contour_limit; contour_idx++) {
      contours[contour_idx] = org_contours[contour_idx];
      if(contours[contour_idx] <= prev_contour) {
        /* unordered contours: this is invalid */
        return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
      }
      prev_contour = contours[contour_idx];
    }
    num_points = 0;
    if(num_contours > 0) {
      num_points = contours[contour_idx - 1] + 1;
      if(num_points < 0) {
        return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
      }
    }

    /* note that we will add four phantom points later */
    points = new FTVectorRec[num_points + 4];
................................................................................
    instructions_length = stream.readShort();
    if(instructions_length > ttface.getMax_profile().getMaxSizeOfInstructions()) {
      return FTError.ErrorTag.GLYPH_TOO_MANY_HINTS;
    }
    if(stream.pos() + instructions_length > limit) {
      return FTError.ErrorTag.GLYPH_TOO_MANY_HINTS;
    }
//    if(!load_flags.contains(NO_AUTOHINT) {
    // we always read the instructions!
      instructions = new byte[instructions_length];
      stream.readByteArray(instructions, instructions_length);
//    }

    /* reading the point tags */
    flag_idx = 0;
    tag_idx = 0;
    tag_limit = num_points;
    flags = new Set[num_points];
    tags = new Set[num_points];
    while(tag_idx < tag_limit) {
      byte ch;
      int count;

      if(stream.pos() + 1 > limit) {
        return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
      }
      ch = (byte)(stream.readByte() & 0xFF);
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("tag: %d 0x%02x", tag_idx, ch)+TTTags.GlyphFlags.GlyphFlagsSetToString(TTTags.GlyphFlags.makeTableTagSet(ch)));
      flags[flag_idx] = TTTags.GlyphFlags.makeTableTagSet(ch);
      tags[tag_idx++] = TTTags.GlyphFlags.makeTableTagSet(ch);
      if((ch & TTTags.GlyphFlags.REPEAT.getVal()) != 0) {
        if(stream.pos() + 1 > limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        count = stream.readByte();
        if(flag_idx + count > tag_limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        while(count > 0) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("tag2: %d 0x%02x", tag_idx, ch)+TTTags.GlyphFlags.GlyphFlagsSetToString(TTTags.GlyphFlags.makeTableTagSet(ch)));
          tags[tag_idx++] = TTTags.GlyphFlags.makeTableTagSet(ch);
          count--;
        }

      }
      flag_idx++;
    }

................................................................................
    points = new FTVectorRec[num_points];
    for(vec_idx = 0; vec_idx < num_points; vec_idx++) {
      points[vec_idx] = new FTVectorRec();
    }
Debug(0, DebugTag.DBG_LOAD_FACE, TAG, "pos before reading x: "+stream.pos());
    /* reading the X coordinates */
    x_coordinates = new int[num_points];


    tag_idx = 0;
    x = 0;
    if(stream.pos() > limit) {
      return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
    }
    for(vec_idx = 0; vec_idx < num_points; vec_idx++) {
      delta = 0;
      tag = tags[vec_idx];
      if(tag.contains(TTTags.GlyphFlags.X_SHORT)) {
        if(stream.pos() + 1 > limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        delta = stream.readByte() & 0xFF;
        if(tag.contains(TTTags.GlyphFlags.X_SAME)) {
          delta = -delta;
        }
      } else {
        if(tag.contains(TTTags.GlyphFlags.X_SAME)) {
          if(stream.pos() + 2 > limit) {
            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].remove(TTTags.GlyphFlags.X_SHORT);
      tags[tag_idx].remove(TTTags.GlyphFlags.X_SAME);
      tag_idx++;
    }

    /* reading the Y coordinates */
    y_coordinates = new int[num_points];


    tag_idx = 0;
    y = 0;
    if(stream.pos() > limit) {
      return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
    }
    for(vec_idx = 0; vec_idx < num_points; vec_idx++) {
      delta = 0;
      tag = tags[vec_idx];
      if(tag.contains(TTTags.GlyphFlags.Y_SHORT)) {
        if(stream.pos() + 1 > limit) {
          return FTError.ErrorTag.GLYPH_INVALID_OUTLINE;
        }
        delta = stream.readByte() & 0xFF;
        if(tag.contains(TTTags.GlyphFlags.Y_SAME)) {
          delta = -delta;
        }
      } else {
        if(tag.contains(TTTags.GlyphFlags.Y_SAME)) {
          if(stream.pos() + 2 > limit) {
            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].remove(TTTags.GlyphFlags.Y_SHORT);
      tags[tag_idx].remove(TTTags.GlyphFlags.Y_SAME);
      tags[tag_idx].remove(TTTags.GlyphFlags.REPEAT);
      tags[tag_idx].remove(TTTags.GlyphFlags.RESERVED1);
      tags[tag_idx].remove(TTTags.GlyphFlags.RESERVED2);
      tag_idx++;
    }

int j;
for( j = 0; j < num_points; j++) {
  Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("tag4: %d 0x%02x", j, TTTags.GlyphFlags.GlyphFlagsSetToInt(tags[j])) + TTTags.GlyphFlags.GlyphFlagsSetToString(tags[j]));
}
    FTTrace.Trace(7, TAG, "loaded");
Debug(0, DebugTag.DBG_LOAD_FACE, TAG, toDebugString());
    return error;
  }

  /* ==================== getContours ================================== */
  public int[] getContours() {
    return contours;
  }
................................................................................

  /* ==================== setInstructions ================================== */
  public void setInstructions(byte[] instructions) {
    this.instructions = instructions;
  }

  /* ==================== getFlags ================================== */
  public Set<TTTags.GlyphFlags>[] getFlags() {
    return flags;
  }

  /* ==================== setFlags ================================== */
  public void setFlags(Set<TTTags.GlyphFlags>[] flags) {
    this.flags = flags;
  }

  /* ==================== getX_coordinates ================================== */
  public int[] getX_coordinates() {
    return x_coordinates;
  }
................................................................................

  /* ==================== setY_coordinates ================================== */
  public void setY_coordinates(int[] y_coordinates) {
    this.y_coordinates = y_coordinates;
  }

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

  /* ==================== getTags ================================== */
  public  Set<TTTags.GlyphFlags>getTag(int tag_idx) {
    return tags[tag_idx];
  }

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

  /* ==================== getPoints ================================== */
  public FTVectorRec[] getPoints() {
    return points;
  }

Changes to afttruetype/TTGlyphSlotRec.java.

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
      } else {
        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);







|
|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
      } else {
        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.                   */
loader.getBase().showLoaderZone("TTLoadGlyph", null);
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);

Changes to afttruetype/TTLoaderRec.java.

761
762
763
764
765
766
767

768
769
770

771
772
773
774
775
776
777
...
968
969
970
971
972
973
974
975

976
977
978
979
980
981
982
   */
  public FTError.ErrorTag TTProcessSimpleGlyph() {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    int n_points;

    n_points = gloader.getCurrent().getN_points();
      /* set phantom points */

    gloader.getCurrent().setPoint(n_points, pp1);
    gloader.getCurrent().setPoint(n_points + 1, pp2);
    gloader.getCurrent().setPoint(n_points + 2, pp3);

    gloader.getCurrent().setTag(n_points, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 1, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 2, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 3, Flags.Curve.CONIC);
    n_points += 4;
    if (!load_flags.contains(Flags.Load.NO_HINTING)) {
      zone.tt_prepare_zone(gloader.getCurrent(), 0, 0);
................................................................................
      glyph.setControl_data(exec.glyphIns);
      glyph.setControl_len(n_ins);
    }
    zone.tt_prepare_zone(gloader.getBase(), start_point, start_contour);
      /* Some points are likely touched during execution of  */
      /* instructions on components.  So let's untouch them. */
    for (i = start_point; i < zone.getN_points(); i++) {
      zone.removeTag(i, Flags.Curve.TOUCH_BOTH);

    }
    zone.setN_points(zone.getN_points() + 4);
    return HintGlyph(true);
  }

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







>



>







 







|
>







761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
...
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
   */
  public FTError.ErrorTag TTProcessSimpleGlyph() {
    FTError.ErrorTag error = FTError.ErrorTag.ERR_OK;
    int n_points;

    n_points = gloader.getCurrent().getN_points();
      /* set phantom points */
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("pp1: %d %d, pp2: %d %d, pp3: %d %d, pp4: %d %d", pp1.getX(), pp1.getY(), pp2.getX(), pp2.getY(), pp3.getX(), pp3.getY(), pp4.getX(), pp4.getY()));
    gloader.getCurrent().setPoint(n_points, pp1);
    gloader.getCurrent().setPoint(n_points + 1, pp2);
    gloader.getCurrent().setPoint(n_points + 2, pp3);
    gloader.getCurrent().setPoint(n_points + 3, pp4);
    gloader.getCurrent().setTag(n_points, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 1, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 2, Flags.Curve.CONIC);
    gloader.getCurrent().setTag(n_points + 3, Flags.Curve.CONIC);
    n_points += 4;
    if (!load_flags.contains(Flags.Load.NO_HINTING)) {
      zone.tt_prepare_zone(gloader.getCurrent(), 0, 0);
................................................................................
      glyph.setControl_data(exec.glyphIns);
      glyph.setControl_len(n_ins);
    }
    zone.tt_prepare_zone(gloader.getBase(), start_point, start_contour);
      /* Some points are likely touched during execution of  */
      /* instructions on components.  So let's untouch them. */
    for (i = start_point; i < zone.getN_points(); i++) {
      zone.removeTag(i, Flags.Curve.TOUCH_X);
      zone.removeTag(i, Flags.Curve.TOUCH_Y);
    }
    zone.setN_points(zone.getN_points() + 4);
    return HintGlyph(true);
  }

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

Changes to afttruetype/TTTags.java.

13
14
15
16
17
18
19



20
21
22
23
24
25
26
....
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
....
1140
1141
1142
1143
1144
1145
1146









1147
1148
1149
1150
1151
1152
1153
....
1164
1165
1166
1167
1168
1169
1170


















1171
1172
1173
1174
1175
1176
1177
 * =====================================================================
 */

import android.util.SparseArray;

import org.apwtcl.apwfreetypelib.aftutil.TTUtil;




public class TTTags {

  /* =========================================================================
     *
     * Possible values of the `name' identifier field in the name records of
     * the TTF `name' table.  These values are platform independent.
     *
................................................................................
    }
    public int getVal() {
      return val;
    }
  }

  public enum GlyphFlags {
    Unknown(0x0, "TT_CMAP_UNKNOWN_FORMAT"),
    ON_CURVE(0x1, "TT_GLYPH_FLAGS_ON_CURVE"),
    X_SHORT(0x2, "TT_GLYPH_FLAGS_X_SHORT"),
    Y_SHORT(0x4, "TT_GLYPH_FLAGS_Y_SHORT"),
    REPEAT(0x8, "TT_GLYPH_FLAGS_REPEAT"),
    X_SAME(0x10, "TT_GLYPH_FLAGS_X_SAME"),
    Y_SAME(0x20, "TT_GLYPH_FLAGS_Y_SAME"),
    RESERVED1(0x40, "TT_GLYPH_FLAGS_RESERVED1"),
................................................................................
    private String str;
    private static SparseArray<GlyphFlags> tagToGlyphFlagsMapping;
    public static GlyphFlags getTableTag(int i) {
      if (tagToGlyphFlagsMapping == null) {
        initMapping();
      }
      return tagToGlyphFlagsMapping.get(i);









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


















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

}







>
>
>







 







|







 







>
>
>
>
>
>
>
>
>







 







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







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
....
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
....
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
....
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
 * =====================================================================
 */

import android.util.SparseArray;

import org.apwtcl.apwfreetypelib.aftutil.TTUtil;

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

public class TTTags {

  /* =========================================================================
     *
     * Possible values of the `name' identifier field in the name records of
     * the TTF `name' table.  These values are platform independent.
     *
................................................................................
    }
    public int getVal() {
      return val;
    }
  }

  public enum GlyphFlags {
    Unknown(0x0, "TT_GLYPH_FLAGS_UNKNOWN"),
    ON_CURVE(0x1, "TT_GLYPH_FLAGS_ON_CURVE"),
    X_SHORT(0x2, "TT_GLYPH_FLAGS_X_SHORT"),
    Y_SHORT(0x4, "TT_GLYPH_FLAGS_Y_SHORT"),
    REPEAT(0x8, "TT_GLYPH_FLAGS_REPEAT"),
    X_SAME(0x10, "TT_GLYPH_FLAGS_X_SAME"),
    Y_SAME(0x20, "TT_GLYPH_FLAGS_Y_SAME"),
    RESERVED1(0x40, "TT_GLYPH_FLAGS_RESERVED1"),
................................................................................
    private String str;
    private static SparseArray<GlyphFlags> tagToGlyphFlagsMapping;
    public static GlyphFlags getTableTag(int i) {
      if (tagToGlyphFlagsMapping == null) {
        initMapping();
      }
      return tagToGlyphFlagsMapping.get(i);
    }
    public static Set<GlyphFlags> makeTableTagSet(int value) {
      Set<GlyphFlags> flags = new HashSet<>();
      for (GlyphFlags t : values()) {
        if ((value & t.getVal()) != 0) {
          flags.add(t);
        }
      }
      return flags;
    }
    private static void initMapping() {
      tagToGlyphFlagsMapping = new SparseArray<GlyphFlags>();
      for (GlyphFlags t : values()) {
        tagToGlyphFlagsMapping.put(t.val, t);
      }
    }
................................................................................
        }
      }
      return str;
    }
    private GlyphFlags(int val, String str) {
      this.val = val;
      this.str = str;
    }
    public static String GlyphFlagsSetToString(Set<GlyphFlags> flags) {
      StringBuffer str = new StringBuffer();
      for (GlyphFlags t : values()) {
        if (flags.contains(t)) {
          str.append(" "+t.toString());
        }
      }
      return str.toString();
    }
    public static int GlyphFlagsSetToInt(Set<GlyphFlags> flags) {
      int val = 0;
      for (GlyphFlags t : values()) {
        if (flags.contains(t)) {
          val += t.getVal();
        }
      }
      return val;
    }
    public int getVal() {
      return val;
    }
  }

}

Changes to aftttinterpreter/TTInstructionFuncGrp3.java.

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
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
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
...
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
    int orus1;
    int orus2;
    int org1;
    int org2;
    int delta1;
    int delta2;

    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("_iup_worker_interpolate: p1: %d, p2: %d, ref1: %d ref2: %d", p1, p2, ref1, ref2));
    if (p1 > p2) {
      return;
    }
    if (TTUtil.BOUNDS(ref1, worker.getMax_points()) ||
        TTUtil.BOUNDS(ref2, worker.getMax_points())) {
      return;
    }
................................................................................
      delta2 = worker.getCurPoint_x(ref2) - org2;
    } else {
      org1   = worker.getOrgPoint_y(ref1);
      org2   = worker.getOrgPoint_y(ref2);
      delta1 = worker.getCurPoint_y(ref1) - org1;
      delta2 = worker.getCurPoint_y(ref2) - org2;
    }
    Debug(0, DebugTag.DBG_INTERP, TAG, String.format("org1: %d,  org2: %d, delta1: %d, delta2: %d, orus1. %d, orus2: %d", org1, org2, delta1, delta2, orus1, orus2));
    if (orus1 == orus2) {
        /* simple shift of untouched points */
      for (i = p1; i <= p2; i++) {
        int x;

        if (useX) {
          x = worker.getOrgPoint_x(i);
................................................................................
          x = worker.getOrgPoint_y(i);
        }
        if (x <= org1) {
          x += delta1;
        } else {
          x += delta2;
        }
        Debug(0, DebugTag.DBG_INTERP, TAG, String.format("i: %d curs[i].x: %d x: %d",  i, useX ? worker.getCurPoint_x(i) : worker.getCurPoint_y(i), x));
        if (useX) {
          worker.setCurPoint_x(i,  x);
        } else {
          worker.setCurPoint_y(i,  x);
        }
      }
    } else {
      int scale = 0;
      boolean scale_valid = false;

      Debug(0, DebugTag.DBG_INTERP, TAG, String.format("p1: %d, p2: %d", p1, p2));
        /* interpolation */
      for (i = p1; i <= p2; i++) {
        int x;

        if (useX) {
          x = worker.getOrgPoint_x(i);
        } else {
          x = worker.getOrgPoint_y(i);
        }
        Debug(0, DebugTag.DBG_INTERP, TAG, String.format("x: %d org1: %d, org2: %d, delta1: %d", x, org1, org2, delta1));
        if (x <= org1) {
          x += delta1;
        } else {
          if (x >= org2) {
            x += delta2;
          } else {
            if (!scale_valid) {
              scale_valid = true;
              scale = FTCalc.FTDivFix(org2 + delta2 - (org1 + delta1), orus2 - orus1);
            }
            Debug(0, DebugTag.DBG_INTERP, TAG, String.format("scale: %d, org1: %d, delta1: %d, worker.orus[i].x: %d, orus1: %d", scale, org1, delta1, useX ?  worker.getOrusPoint_x(i) :  worker.getOrusPoint_y(i), orus1));
            if (useX) {
              x = (org1 + delta1) + TTUtil.FTMulFix(worker.getOrusPoint_x(i) - orus1, scale);
            } else {
              x = (org1 + delta1) + TTUtil.FTMulFix(worker.getOrusPoint_y(i) - orus1, scale);
            }
            Debug(0, DebugTag.DBG_INTERP, TAG, String.format("x: %d", x));
          }
        }
        if (useX) {
          worker.setCurPoint_x(i, x);
        } else {
          worker.setCurPoint_y(i, x);
        }
................................................................................
    int end_point;     /* end point (last+1) of contour */
    int first_touched; /* first touched point in contour   */
    int cur_touched;   /* current touched point in contour */
    int point;         /* current point   */
    int contour;       /* current contour */
    boolean useX;

Debug(0, DebugTag.DBG_INTERP, TAG, "IUP");
      /* ignore empty outlines */
    if (cur.pts.getN_contours() == 0) {
      return;
    }
//FTGlyphLoaderRec._showLoaderZone("insIUP");
    if ((cur.opcode.getVal() & 1) != 0) {
      useX = true;
................................................................................
      V.setOrus(cur.pts.getOrus());
      V.setOrus_idx(cur.pts.getOrus_idx());
    }
    V.setMax_points(cur.pts.getN_points());
    contour = 0;
    point = 0;
    do {
      end_point = cur.pts.getContours()[contour] - cur.pts.getFirst_point();

      first_point = point;
      if (TTUtil.BOUNDS(end_point, cur.pts.getN_points())) {
        end_point = cur.pts.getN_points() - 1;
      }


      while (point <= end_point && !cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X)) {

        point++;
      }

      worker_ref = new FTReference<>();
      worker_ref.Set(V);
      if (point <= end_point) {
        first_touched = point;
        cur_touched   = point;
        point++;

        while (point <= end_point) {

          if (cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X)) {
            _iup_worker_interpolate(worker_ref, cur_touched + 1, point - 1, cur_touched, point, useX);
            cur_touched = point;
          }
          point++;
        }
        if (cur_touched == first_touched) {
          _iup_worker_shift(worker_ref, first_point, end_point, cur_touched, useX);







|







 







|







 







|










|









|










|





|







 







|







 







|
>




>
>
|
>


>






>

>
|







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
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
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
...
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
    int orus1;
    int orus2;
    int org1;
    int org2;
    int delta1;
    int delta2;

Debug(0, DebugTag.DBG_INTERP, TAG, String.format("_iup_worker_interpolate: p1: %d, p2: %d, ref1: %d ref2: %d", p1, p2, ref1, ref2));
    if (p1 > p2) {
      return;
    }
    if (TTUtil.BOUNDS(ref1, worker.getMax_points()) ||
        TTUtil.BOUNDS(ref2, worker.getMax_points())) {
      return;
    }
................................................................................
      delta2 = worker.getCurPoint_x(ref2) - org2;
    } else {
      org1   = worker.getOrgPoint_y(ref1);
      org2   = worker.getOrgPoint_y(ref2);
      delta1 = worker.getCurPoint_y(ref1) - org1;
      delta2 = worker.getCurPoint_y(ref2) - org2;
    }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("org1: %d,  org2: %d, delta1: %d, delta2: %d, orus1. %d, orus2: %d", org1, org2, delta1, delta2, orus1, orus2));
    if (orus1 == orus2) {
        /* simple shift of untouched points */
      for (i = p1; i <= p2; i++) {
        int x;

        if (useX) {
          x = worker.getOrgPoint_x(i);
................................................................................
          x = worker.getOrgPoint_y(i);
        }
        if (x <= org1) {
          x += delta1;
        } else {
          x += delta2;
        }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("i: %d curs[i].x: %d x: %d",  i, useX ? worker.getCurPoint_x(i) : worker.getCurPoint_y(i), x));
        if (useX) {
          worker.setCurPoint_x(i,  x);
        } else {
          worker.setCurPoint_y(i,  x);
        }
      }
    } else {
      int scale = 0;
      boolean scale_valid = false;

Debug(0, DebugTag.DBG_INTERP, TAG, String.format("p1: %d, p2: %d", p1, p2));
        /* interpolation */
      for (i = p1; i <= p2; i++) {
        int x;

        if (useX) {
          x = worker.getOrgPoint_x(i);
        } else {
          x = worker.getOrgPoint_y(i);
        }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("x: %d org1: %d, org2: %d, delta1: %d", x, org1, org2, delta1));
        if (x <= org1) {
          x += delta1;
        } else {
          if (x >= org2) {
            x += delta2;
          } else {
            if (!scale_valid) {
              scale_valid = true;
              scale = FTCalc.FTDivFix(org2 + delta2 - (org1 + delta1), orus2 - orus1);
            }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("scale: %d, org1: %d, delta1: %d, worker.orus[i].x: %d, orus1: %d", scale, org1, delta1, useX ?  worker.getOrusPoint_x(i) :  worker.getOrusPoint_y(i), orus1));
            if (useX) {
              x = (org1 + delta1) + TTUtil.FTMulFix(worker.getOrusPoint_x(i) - orus1, scale);
            } else {
              x = (org1 + delta1) + TTUtil.FTMulFix(worker.getOrusPoint_y(i) - orus1, scale);
            }
Debug(0, DebugTag.DBG_INTERP, TAG, String.format("x: %d", x));
          }
        }
        if (useX) {
          worker.setCurPoint_x(i, x);
        } else {
          worker.setCurPoint_y(i, x);
        }
................................................................................
    int end_point;     /* end point (last+1) of contour */
    int first_touched; /* first touched point in contour   */
    int cur_touched;   /* current touched point in contour */
    int point;         /* current point   */
    int contour;       /* current contour */
    boolean useX;

Debug(0, DebugTag.DBG_INTERP, TAG, "IUP opcode: "+cur.opcode);
      /* ignore empty outlines */
    if (cur.pts.getN_contours() == 0) {
      return;
    }
//FTGlyphLoaderRec._showLoaderZone("insIUP");
    if ((cur.opcode.getVal() & 1) != 0) {
      useX = true;
................................................................................
      V.setOrus(cur.pts.getOrus());
      V.setOrus_idx(cur.pts.getOrus_idx());
    }
    V.setMax_points(cur.pts.getN_points());
    contour = 0;
    point = 0;
    do {
      end_point = cur.pts.getContour(contour) - cur.pts.getFirst_point();
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("end_point: %d, contour: %d, first_point: %d", end_point, cur.pts.getContour(contour), cur.pts.getFirst_point()));
      first_point = point;
      if (TTUtil.BOUNDS(end_point, cur.pts.getN_points())) {
        end_point = cur.pts.getN_points() - 1;
      }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("point: %d, end_point: %d", point, end_point));
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tag1: point: "+point+" tags: "+Flags.Curve.CurveSetToString(cur.pts.getTag(point))+" mask: "+mask+" "+cur.pts.getTag(point).contains(mask)+" "+cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X)+" "+cur.pts.getTag(point).contains(Flags.Curve.TOUCH_Y));
      while (point <= end_point && !cur.pts.getTag(point).contains(mask)) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tag2: point: "+point+" "+Flags.Curve.CurveSetToString(cur.pts.getTag(point)));
        point++;
      }
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("point2: %d, end_point: %d", point, end_point));
      worker_ref = new FTReference<>();
      worker_ref.Set(V);
      if (point <= end_point) {
        first_touched = point;
        cur_touched   = point;
        point++;
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, String.format("point3: %d, end_point: %d, cur_touched: %d", point, end_point, cur_touched));
        while (point <= end_point) {
Debug(0, DebugTag.DBG_LOAD_GLYPH, TAG, "tag3: point: "+point+" "+Flags.Curve.CurveSetToString(cur.pts.getTag(point))+" "+mask+" "+cur.pts.getTag(point).contains(mask)+" "+cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X)+" "+cur.pts.getTag(point).contains(Flags.Curve.TOUCH_X));
          if (cur.pts.getTag(point).contains(mask)) {
            _iup_worker_interpolate(worker_ref, cur_touched + 1, point - 1, cur_touched, point, useX);
            cur_touched = point;
          }
          point++;
        }
        if (cur_touched == first_touched) {
          _iup_worker_shift(worker_ref, first_point, end_point, cur_touched, useX);

Changes to aftttinterpreter/TTMoveYFunc.java.

55
56
57
58
59
60
61
62
63
64


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


  }

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







|


>
>







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

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

Changes to aftttinterpreter/TTRunInstructions.java.

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







|







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