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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* GlyphLoader.java -- Helper for loading TrueType glyph outlines.
2
   Copyright (C) 2006 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package gnu.java.awt.font.opentype.truetype;
40
 
41
import gnu.java.awt.font.opentype.Hinter;
42
 
43
import java.awt.geom.AffineTransform;
44
import java.nio.ByteBuffer;
45
 
46
 
47
/**
48
 * A class for loading scaled and hinted glyph outlines.
49
 *
50
 * <p><b>Lack of Thread Safety:</b> Glyph loaders are intentionally
51
 * <i>not</i> safe to access from multiple concurrent
52
 * threads. Synchronization needs to be performed externally. Usually,
53
 * the font has already obtained a lock before calling the scaler,
54
 * which in turn calls the GlyphLoader. It would thus be wasteful to
55
 * acquire additional locks for the GlyphLoader.
56
 *
57
 * @author Sascha Brawer (brawer@dandelis.ch)
58
 */
59
final class GlyphLoader
60
{
61
  /**
62
   * A helper object for locating glyph data. GlyphLocator is an
63
   * abstract superclass, and there is a concretization for each glyph
64
   * location table ('loca') format.
65
   */
66
  private final GlyphLocator glyphLocator;
67
 
68
 
69
  /**
70
   * A helper object for measuring the advance width and height of a
71
   * glyph.
72
   */
73
  private final GlyphMeasurer glyphMeasurer;
74
 
75
 
76
  /**
77
   * The virtual machine for executing TrueType bytecodes.
78
   */
79
  private final VirtualMachine vm;
80
 
81
 
82
  /**
83
   * The number of font units in one em. A typical value is 2048,
84
   * but this depends on the font.
85
   */
86
  private final int unitsPerEm;
87
 
88
  private final int[] contourEndPoints;
89
  private final byte[] pointFlags;
90
 
91
 
92
  /**
93
   * Constructs a GlyphLoader.
94
   */
95
  GlyphLoader(GlyphLocator glyphLocator, VirtualMachine vm,
96
              int unitsPerEm, int maxContours, int maxPoints,
97
              GlyphMeasurer glyphMeasurer)
98
  {
99
    this.glyphLocator = glyphLocator;
100
    this.glyphMeasurer = glyphMeasurer;
101
    this.unitsPerEm = unitsPerEm;
102
    this.vm = vm;
103
 
104
    contourEndPoints = new int[maxContours];
105
    pointFlags = new byte[maxPoints];
106
  }
107
 
108
 
109
  /**
110
   * @param glyphIndex the number of the glyph whose outlines are to be
111
   * retrieved.
112
   */
113
  public void loadGlyph(int glyphIndex,
114
                        double pointSize,
115
                        AffineTransform transform,
116
                        boolean antialias,
117
                        Zone glyphZone, Hinter hinter)
118
  {
119
    glyphZone.setNumPoints(4);
120
    loadSubGlyph(glyphIndex, pointSize, transform, antialias, glyphZone,
121
                 0, 0, hinter);
122
  }
123
 
124
  public void loadGlyph(int glyphIndex, AffineTransform transform,
125
                        Zone glyphZone, Hinter hinter)
126
  {
127
    loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone, hinter);
128
  }
129
 
130
  private void loadSubGlyph(int glyphIndex,
131
                            double pointSize,
132
                            AffineTransform transform,
133
                            boolean antialias,
134
                            Zone glyphZone,
135
                            int preTranslateX,
136
                            int preTranslateY,
137
                            Hinter hinter)
138
  {
139
    ByteBuffer glyph;
140
    int numContours;
141
    int xMin, yMin, xMax, yMax;
142
    byte flag;
143
 
144
    glyph = glyphLocator.getGlyphData(glyphIndex);
145
 
146
    if (glyph == null)
147
    {
148
      glyphZone.setNumPoints(4);
149
      setPhantomPoints(glyphIndex, 0, glyphZone);
150
      glyphZone.transform(pointSize, transform, unitsPerEm,
151
                          preTranslateX, preTranslateY);
152
      return;
153
    }
154
 
155
    numContours = glyph.getShort();
156
    xMin = glyph.getChar();
157
    yMin = glyph.getChar();
158
    xMax = glyph.getChar();
159
    yMax = glyph.getChar();
160
 
161
 
162
    if (numContours >= 0)
163
      loadSimpleGlyph(glyphIndex, pointSize, transform, antialias,
164
                      numContours, glyph, glyphZone,
165
                      preTranslateX, preTranslateY, hinter);
166
    else
167
      loadCompoundGlyph(glyphIndex, pointSize, transform, antialias,
168
                        glyph, glyphZone,
169
                        preTranslateX, preTranslateY, hinter);
170
  }
171
 
172
 
173
  private void loadSimpleGlyph(int glyphIndex,
174
                               double pointSize, AffineTransform transform,
175
                               boolean antialias,
176
                               int numContours, ByteBuffer glyph,
177
                               Zone glyphZone,
178
                               int preTranslateX, int preTranslateY,
179
                               Hinter hinter)
180
  {
181
    int numPoints;
182
    int posInstructions, numInstructions;
183
    boolean execInstructions;
184
 
185
    execInstructions = vm.setup(pointSize, transform, antialias);
186
 
187
    /* Load the contour end points and determine the number of
188
     * points.
189
     */
190
    for (int i = 0; i < numContours; i++)
191
      contourEndPoints[i] = glyph.getChar();
192
    if (numContours > 0)
193
      numPoints = 1 + contourEndPoints[numContours - 1];
194
    else
195
      numPoints = 0;
196
    glyphZone.setNumPoints(numPoints + 4);
197
 
198
    numInstructions = glyph.getChar();
199
    posInstructions = glyph.position();
200
    glyph.position(posInstructions + numInstructions);
201
    loadFlags(numPoints, glyph);
202
    loadCoordinates(numPoints, glyph, glyphZone);
203
    for (int i = 0; i < numContours; i++)
204
      glyphZone.setContourEnd(contourEndPoints[i], true);
205
 
206
    setPhantomPoints(glyphIndex, numPoints, glyphZone);
207
    glyphZone.transform(pointSize, transform, unitsPerEm,
208
                        preTranslateX, preTranslateY);
209
 
210
    if (execInstructions && hinter != null)
211
      {
212
        hinter.applyHints(glyphZone);
213
      }
214
  }
215
 
216
 
217
  private static final short ARGS_ARE_WORDS = 1;
218
  private static final short ARGS_ARE_XY_VALUES = 2;
219
  private static final short ROUND_XY_TO_GRID = 4;
220
  private static final short WE_HAVE_A_SCALE = 8;
221
  private static final short MORE_COMPONENTS = 32;
222
  private static final short WE_HAVE_AN_X_AND_Y_SCALE = 64;
223
  private static final short WE_HAVE_A_TWO_BY_TWO = 128;
224
  private static final short WE_HAVE_INSTRUCTIONS = 256;
225
  private static final short USE_MY_METRICS = 512;
226
  private static final short OVERLAP_COMPOUND = 1024;
227
  private static final short SCALED_COMPONENT_OFFSET = 2048;
228
  private static final short UNSCALED_COMPONENT_OFFSET = 4096;
229
 
230
  private void loadCompoundGlyph(int glyphIndex,
231
                                 double pointSize,
232
                                 AffineTransform transform,
233
                                 boolean antialias,
234
                                 ByteBuffer glyph,
235
                                 Zone glyphZone,
236
                                 int preTranslateX, int preTranslateY,
237
                                 Hinter hinter)
238
  {
239
    short flags;
240
    int subGlyphIndex;
241
    int metricsGlyphIndex;
242
    Zone subGlyphZone = new Zone(glyphZone.getCapacity());
243
    int arg1, arg2;
244
    double a, b, c, d, e, f;
245
    AffineTransform componentTransform = new AffineTransform();
246
 
247
    /* By default, use the metrics of the compound glyph. The default
248
     * is overridden if some component glyph has the USE_MY_METRICS
249
     * flag set.
250
     */
251
    metricsGlyphIndex = glyphIndex;
252
 
253
    do
254
    {
255
      flags = glyph.getShort();
256
      subGlyphIndex = glyph.getChar();
257
 
258
      if ((flags & USE_MY_METRICS) != 0)
259
        metricsGlyphIndex = subGlyphIndex;
260
 
261
      if ((flags & ARGS_ARE_WORDS) != 0)
262
      {
263
        arg1 = glyph.getShort();
264
        arg2 = glyph.getShort();
265
      }
266
      else
267
      {
268
        arg1 = glyph.get();
269
        arg2 = glyph.get();
270
      }
271
 
272
      if ((flags & WE_HAVE_A_SCALE) != 0)
273
      {
274
        a = d = getDouble214(glyph);
275
        b = c = 0.0;
276
      }
277
      else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0)
278
      {
279
        a = getDouble214(glyph);
280
        d = getDouble214(glyph);
281
        b = c = 0.0;
282
      }
283
      else if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0)
284
      {
285
        a = getDouble214(glyph);
286
        b = getDouble214(glyph);
287
        c = getDouble214(glyph);
288
        d = getDouble214(glyph);
289
      }
290
      else
291
      {
292
        a = d = 1.0;
293
        b = c = 0.0;
294
      }
295
 
296
      double m = Math.max(Math.abs(a), Math.abs(b));
297
      double n = Math.max(Math.abs(c), Math.abs(d));
298
 
299
      /* The Apple TrueType specification actually says that m is
300
       * multiplied by two if
301
       *
302
       *        abs(abs(a) - abs(c)) <= 33/65536,
303
       *
304
       * but this is probably a typo. On 2003-07-23, Sascha Brawer
305
       * wrote an e-mail message to applefonts@apple.com, asking
306
       * whether this might possibly be an error in the specification.
307
       */
308
      if (Math.abs(Math.abs(a) - Math.abs(b)) <= 33.0/65536.0)
309
        m = m * 2;
310
 
311
      if (Math.abs(Math.abs(c) - Math.abs(d)) <= 33.0/65536.0)
312
        n = n * 2;
313
 
314
      if ((flags & ARGS_ARE_XY_VALUES) != 0)
315
      {
316
        e = m * arg1;
317
        f = n * arg2;
318
      }
319
      else
320
        e = f = 0.0;
321
 
322
      componentTransform.setTransform(a, b, c, d, 0.0, 0.0);
323
 
324
      // System.out.println("componentTransform = " + componentTransform
325
      //   + ", e=" + e + ", f=" + f);
326
      componentTransform.concatenate(transform);
327
 
328
      int pos = glyph.position();
329
      int lim = glyph.limit();
330
 
331
      loadSubGlyph(subGlyphIndex, pointSize, componentTransform,
332
                   antialias, subGlyphZone,
333
                   Math.round((float) e + preTranslateX),
334
                   Math.round(-((float) f + preTranslateY)), hinter);
335
      glyphZone.combineWithSubGlyph(subGlyphZone, 4);
336
      glyph.limit(lim).position(pos);
337
    }
338
    while ((flags & MORE_COMPONENTS) != 0);
339
 
340
    setPhantomPoints(metricsGlyphIndex, glyphZone.getSize() - 4, glyphZone);
341
  }
342
 
343
 
344
  private double getDouble214(ByteBuffer buf)
345
  {
346
    return ((double) buf.getShort()) / (1 << 14);
347
  }
348
 
349
 
350
  /**
351
   * Loads the per-point flags of a glyph into the
352
   * <code>pointFlags</code> field.
353
   */
354
  private void loadFlags(int numPoints, ByteBuffer glyph)
355
  {
356
    byte flag;
357
    int numRepetitions;
358
 
359
    for (int i = 0; i < numPoints; i++)
360
    {
361
      pointFlags[i] = flag = glyph.get();
362
      if ((flag & 8) != 0)
363
      {
364
        numRepetitions = ((int) glyph.get()) & 0xff;
365
        while (numRepetitions > 0)
366
        {
367
          pointFlags[++i] = flag;
368
          --numRepetitions;
369
        }
370
      }
371
    }
372
  }
373
 
374
 
375
  private void loadCoordinates(int numPoints, ByteBuffer glyph,
376
                               Zone glyphZone)
377
  {
378
    int x, y;
379
    byte flag;
380
 
381
    x = 0;
382
    for (int i = 0; i < numPoints; i++)
383
    {
384
      flag = pointFlags[i];
385
      if ((flag & 2) == 0)
386
      {
387
        if ((flag & 16) == 0)
388
          x += glyph.getShort();
389
      }
390
      else
391
      {
392
        if ((flag & 16) != 0)
393
          x += (glyph.get() & 0xff);
394
        else
395
          x -= (glyph.get() & 0xff);
396
      }
397
      glyphZone.setOriginalX(i, x);
398
      glyphZone.setOnCurve(i, (flag & 1) == 1);
399
    }
400
 
401
    y = 0;
402
    for (int i = 0; i < numPoints; i++)
403
    {
404
      flag = pointFlags[i];
405
      if ((flag & 4) == 0)
406
      {
407
        if ((flag & 32) == 0)
408
          y += glyph.getShort();
409
      }
410
      else
411
      {
412
        if ((flag & 32) != 0)
413
          y += (glyph.get() & 0xff);
414
        else
415
          y -= (glyph.get() & 0xff);
416
      }
417
      glyphZone.setOriginalY(i, -y);
418
    }
419
  }
420
 
421
 
422
  private void setPhantomPoints(int glyphIndex, int numPoints,
423
                                Zone glyphZone)
424
  {
425
    /* Phantom point 0: Character origin. */
426
    glyphZone.setOriginalX(numPoints, 0);
427
    glyphZone.setOriginalY(numPoints, 0);
428
 
429
    /* Phantom point 1: Horizontal advance point. */
430
    glyphZone.setOriginalX(numPoints + 1,
431
                   glyphMeasurer.getAdvanceWidth(glyphIndex, true));
432
    glyphZone.setOriginalY(numPoints + 1,
433
                           glyphMeasurer.getAdvanceHeight(glyphIndex, true));
434
 
435
    /* Phantom point 2: Vertical origin. */
436
    int vertX = glyphMeasurer.getAscent(/* vertical */ false);
437
    int vertY = glyphMeasurer.getAscent(/* horizontal */ true);
438
    glyphZone.setOriginalX(numPoints + 2, vertX);
439
    glyphZone.setOriginalY(numPoints + 2, vertY);
440
 
441
    /* Phantom point 3: Vertical advance point. */
442
    glyphZone.setOriginalX(numPoints + 3,
443
                           vertX + glyphMeasurer.getAdvanceWidth(glyphIndex, false));
444
    glyphZone.setOriginalY(numPoints + 3,
445
                           vertY + glyphMeasurer.getAdvanceHeight(glyphIndex, false));
446
  }
447
}

powered by: WebSVN 2.1.0

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