summaryrefslogtreecommitdiff
path: root/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java
blob: 8dfdeff0790018874bafecb987ae4ed2e80b739f (plain)
1
2
3
4
5
6
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
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
/* TrueTypeScaler.java -- Font scaler for TrueType outlines.
   Copyright (C) 2006 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package gnu.java.awt.font.opentype.truetype;

import gnu.java.awt.font.opentype.Scaler;

import java.awt.FontFormatException;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;


/**
 * A scaler for fonts whose outlines are described in the TrueType
 * format.
 *
 * <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
 * <i>not</i> safe to access from multiple concurrent threads.
 * Synchronization needs to be performed externally. Usually, the font
 * that uses this scaler already has obtained a lock before calling
 * the scaler.
 *
 * @author Sascha Brawer (brawer@dandelis.ch)
 */
public final class TrueTypeScaler
  extends Scaler
{
  /**
   * The TrueType or OpenType table that contains the glyph outlines.
   */
  private ByteBuffer glyfTable;


  /**
   * A helper object for loading glyph outlines.
   */
  private GlyphLoader glyphLoader;


  /**
   * A helper object for measuring the advance width and height of a
   * glyph.
   */
  private final GlyphMeasurer glyphMeasurer;

  private final Zone glyphZone;


  /**
   * The number of units per em. A typical value is 2048, but some
   * font use other numbers as well.
   */
  private int unitsPerEm;


  /**
   * Constructs a new TrueTypeScaler.
   *
   * @param unitsPerEm the number of font units per em. This value can
   * be retrieved from the font&#x2019;s <code>head</code> table.
   *
   * @param maxp the <code>maxp</code> table of the font, which
   * contains various constants needed for setting up the virtual
   * machine that interprets TrueType bytecodes.
   *
   * @param controlValueTable the <code>cvt</code> table of the font,
   * which contains the initial values of the control value table.
   *
   * @param fpgm the <code>fpgm</code> table of the font, which
   * contains a font program that is executed exactly once.  The
   * purpose of the font program is to define functions and to patch
   * the interpreter.
   *
   * @param locaFormat the format of the <code>loca</code> table.  The
   * value must be 0 for two-byte offsets, or 1 for four-byte
   * offsets. TrueType and OpenType fonts indicate the format in the
   * <code>indexToLoc</code> field of the <a href=
   * "http://partners.adobe.com/asn/tech/type/opentype/head.html"
   * >font header</a>.
   *
   * @param loca the <code>loca</code> table of the font, which
   * contains for each glyph the offset of its outline data
   * in <code>glyf</code>.
   *
   * @param glyf the <code>glyf</code> table of the font, which
   * contains the outline data for all glyphs in the font.
   *
   * @param preProgram the <code>prep</code> table of the font, which
   * contains a program that is executed whenever the point size or
   * the device transform have changed.  This program is called
   * pre-program because it gets executed before the instructions of
   * the individual glyphs.  If the font does not contain a
   * pre-program, pass <code>null</code>.
   *
   * @throws FontFormatException if <code>format</code> is neither 0
   * nor 1.
   */
  public TrueTypeScaler(int unitsPerEm,
                        ByteBuffer hhea,
                        ByteBuffer htmx,
                        ByteBuffer vhea,
                        ByteBuffer vtmx,
                        ByteBuffer maxp,                        
                        ByteBuffer controlValueTable,
                        ByteBuffer fpgm,
                        int locaFormat, ByteBuffer loca,
                        ByteBuffer glyf,
                        ByteBuffer preProgram)
    throws FontFormatException
  {
    int maxContours, maxPoints;
    VirtualMachine vm;

    maxContours = Math.max(/* maxContours */ (int) maxp.getChar(8),
                           /* maxCompositeContours */ (int) maxp.getChar(12))
      + /* fix for some broken fonts */ 8;
    maxPoints = Math.max(/* maxPoints */ (int) maxp.getChar(6),
                         /* maxCompositePoints */ (int) maxp.getChar(10))
      + /* fix for some broken fonts */ 12;


    glyphZone = new Zone(maxPoints + /* four phantom points */ 4);
    this.glyfTable = glyf;
    vm = new VirtualMachine(unitsPerEm, maxp,
                            controlValueTable, fpgm,
                            preProgram);

    GlyphLocator locator = GlyphLocator.forTable(locaFormat, loca, glyf);
    glyphMeasurer = new GlyphMeasurer(hhea, htmx, vhea, vtmx);
    glyphLoader = new GlyphLoader(locator, vm, unitsPerEm,
                                  maxContours, maxPoints,
                                  glyphMeasurer);

    this.unitsPerEm = unitsPerEm;
  }


  /**
   * Retrieves the scaled outline of a glyph, adjusting control points
   * to the raster grid if necessary.
   *
   * @param glyphIndex the glyph number whose outline is retrieved.
   *
   * @param pointSize the point size for the glyph.
   *
   * @param deviceTransform an affine transformation for the device.
   *
   * @param antialias whether or not the rasterizer will perform
   * anti-aliasing on the returned path.
   *
   * @param fractionalMetrics <code>false</code> for adjusting glyph
   * positions to the raster grid of device space.
   */
  public GeneralPath getOutline(int glyphIndex,
                                float pointSize,
                                AffineTransform deviceTransform,
                                boolean antialias,
                                boolean fractionalMetrics)
  {
    glyphLoader.loadGlyph(glyphIndex, pointSize, deviceTransform,
                          antialias, glyphZone);
    return glyphZone.getPath();
  }

  public Zone getRawOutline(int glyphIndex, AffineTransform transform)
  {
    Zone zone = new Zone(glyphZone.getCapacity());
    glyphLoader.loadGlyph(glyphIndex, transform, zone);
    return zone;
  }

  /**
   * Determines the advance width and height for a glyph.
   *
   * @param glyphIndex the glyph whose advance width and height is to
   * be determined.
   *
   * @param pointSize the point size of the font.
   *
   * @param transform a transform that is applied in addition to
   * scaling to the specified point size. This is often used for
   * scaling according to the device resolution. Those who lack any
   * aesthetic sense may also use the transform to slant or stretch
   * glyphs.
   *
   * @param antialias <code>true</code> for anti-aliased rendering,
   * <code>false</code> for normal rendering. For hinted fonts,
   * this parameter may indeed affect the result.
   *
   * @param fractionalMetrics <code>true</code> for fractional metrics,
   * <code>false</code> for rounding the result to a pixel boundary.
   *
   * @param horizontal <code>true</code> for horizontal line layout,
   * <code>false</code> for vertical line layout.
   *
   * @param advance a point whose <code>x</code> and <code>y</code>
   * fields will hold the advance in each direction. It is possible
   * that both values are non-zero, for example if
   * <code>transform</code> is a rotation, or in the case of Urdu
   * fonts.
   */
  public void getAdvance(int glyphIndex,
                         float pointSize,
                         AffineTransform transform,
                         boolean antialias,
                         boolean fractionalMetrics,
                         boolean horizontal,
                         Point2D advance)
  {
    double x, y;
    double scaleFactor = (double) pointSize / unitsPerEm;

    /* FIXME: Should grid-fit if needed. Also, use cache if present
     * in the font.
     */
    advance.setLocation(
      scaleFactor * glyphMeasurer.getAdvanceWidth(glyphIndex, horizontal),
      scaleFactor * glyphMeasurer.getAdvanceHeight(glyphIndex, horizontal));
    
    transform.transform(advance, advance);
  }


  /**
   * Scales a value from font units to pixels, given the point size
   * and the transform.
   *
   * @param pointSize the point size of the font.
   *
   * @param transform a transform that is applied in addition to
   * scaling to the specified point size. This is often used for
   * scaling according to the device resolution.
   *
   * @param fractionalMetrics <code>true</code> for fractional
   * metrics, <code>false</code> for rounding the result to a pixel
   * boundary.
   *
   * @param horizontal <code>true</code> if the <code>funits</code>
   * value is along the x axis, <code>false</code> if it is along the
   * y axis.
   */
  private float scaleFromFUnits(int funits,
                                float pointSize,
                                AffineTransform transform,
                                boolean fractionalMetrics,
                                boolean horizontal)
  {
    double s;

    s = (double) pointSize / unitsPerEm;
    if (transform != null)
      s *= horizontal ? transform.getScaleY() : transform.getScaleX();
    s *= funits;
    if (!fractionalMetrics)
      s = Math.round(s);
    return (float) s;
  }


  /**
   * Determines the distance between the base line and the highest
   * ascender.
   *
   * @param pointSize the point size of the font.
   *
   * @param transform a transform that is applied in addition to
   * scaling to the specified point size. This is often used for
   * scaling according to the device resolution. Those who lack any
   * aesthetic sense may also use the transform to slant or stretch
   * glyphs.
   *
   * @param antialias <code>true</code> for anti-aliased rendering,
   * <code>false</code> for normal rendering. For hinted fonts,
   * this parameter may indeed affect the result.
   *
   * @param fractionalMetrics <code>true</code> for fractional metrics,
   * <code>false</code> for rounding the result to a pixel boundary.
   *
   * @param horizontal <code>true</code> for horizontal line layout,
   * <code>false</code> for vertical line layout.
   *
   * @return the ascent, which usually is a positive number.
   */
  public float getAscent(float pointSize,
                         AffineTransform transform,
                         boolean antialias,
                         boolean fractionalMetrics,
                         boolean horizontal)
  {
    /* Note that the ascent is orthogonal to the direction of line
     * layout: If the line direction is horizontal, the measurement of
     * ascent is along the vertical axis, and vice versa.
     */
    return scaleFromFUnits(glyphMeasurer.getAscent(horizontal),
                           pointSize,
                           transform,
                           fractionalMetrics,
                           /* reverse */ !horizontal);
  }


  /**
   * Determines the distance between the base line and the lowest
   * descender.
   *
   * @param pointSize the point size of the font.
   *
   * @param transform a transform that is applied in addition to
   * scaling to the specified point size. This is often used for
   * scaling according to the device resolution. Those who lack any
   * aesthetic sense may also use the transform to slant or stretch
   * glyphs.
   *
   * @param antialiased <code>true</code> for anti-aliased rendering,
   * <code>false</code> for normal rendering. For hinted fonts,
   * this parameter may indeed affect the result.
   *
   * @param fractionalMetrics <code>true</code> for fractional metrics,
   * <code>false</code> for rounding the result to a pixel boundary.
   *
   * @param horizontal <code>true</code> for horizontal line layout,
   * <code>false</code> for vertical line layout.
   *
   * @return the descent, which usually is a nagative number.
   */
  public float getDescent(float pointSize,
                          AffineTransform transform,
                          boolean antialiased,
                          boolean fractionalMetrics,
                          boolean horizontal)
  {
    /* Note that the descent is orthogonal to the direction of line
     * layout: If the line direction is horizontal, the measurement of
     * descent is along the vertical axis, and vice versa.
     */
    return scaleFromFUnits(glyphMeasurer.getDescent(horizontal),
                           pointSize,
                           transform,
                           fractionalMetrics,
                           /* reverse */ !horizontal);
  }
}