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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [java/] [awt/] [peer/] [gtk/] [FreetypeGlyphVector.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* FreetypeGlyphVector.java
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
package gnu.java.awt.peer.gtk;
39
 
40
import java.awt.Font;
41
import java.awt.Shape;
42
import java.awt.font.FontRenderContext;
43
import java.awt.font.GlyphJustificationInfo;
44
import java.awt.font.GlyphMetrics;
45
import java.awt.font.GlyphVector;
46
import java.awt.font.TextAttribute;
47
import java.awt.font.TransformAttribute;
48
import java.awt.geom.AffineTransform;
49
import java.awt.geom.GeneralPath;
50
import java.awt.geom.Point2D;
51
import java.awt.geom.Rectangle2D;
52
import java.util.Arrays;
53
 
54
public class FreetypeGlyphVector extends GlyphVector
55
{
56
  /**
57
   * The associated font and its peer.
58
   */
59
  private Font font;
60
  private GdkFontPeer peer; // ATTN: Accessed from native code.
61
 
62
  private Rectangle2D logicalBounds;
63
 
64
  private float[] glyphPositions;
65
  /**
66
   * The string represented by this GlyphVector.
67
   */
68
  private String s;
69
 
70
  /**
71
   * The font render context
72
   */
73
  private FontRenderContext frc;
74
 
75
  /**
76
   * The total # of glyphs.
77
   */
78
  private int nGlyphs;
79
 
80
  /**
81
   * The glyph codes
82
   */
83
  private int[] glyphCodes;
84
 
85
  /**
86
   * The set of fonts used in this glyph vector.
87
   */
88
  private long[] fontSet = null;
89
 
90
  /**
91
   * Glyph transforms.  Supports all transform operations.
92
   *
93
   * The identity transform should not be stored in this array; use a null
94
   * instead (will result in performance improvements).
95
   */
96
  private AffineTransform[] glyphTransforms;
97
 
98
  private GlyphMetrics[] metricsCache;
99
 
100
  private native void dispose(long[] fonts);
101
 
102
  /**
103
   * Returns a pointer to the native PangoFcFont object.
104
   *
105
   * The object will be referenced with g_object_ref n times before being
106
   * returned, and must be unreferenced a corresponding number of times.
107
   *
108
   * @param n Number of times to reference the object.
109
   * @return Pointer to the native default font.
110
   */
111
  private native long getNativeFontPointer(int n);
112
 
113
  /**
114
   * Create a glyphvector from a given (Freetype) font and a String.
115
   */
116
  public FreetypeGlyphVector(Font f, String s, FontRenderContext frc)
117
  {
118
    this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT);
119
  }
120
 
121
  /**
122
   * Create a glyphvector from a given (Freetype) font and a String.
123
   */
124
  public FreetypeGlyphVector(Font f, char[] chars, int start, int len,
125
                             FontRenderContext frc, int flags)
126
  {
127
    this.s = new String(chars, start, len);
128
 
129
    this.font = f;
130
    this.frc = frc;
131
    if( !(font.getPeer() instanceof GdkFontPeer ) )
132
      throw new IllegalArgumentException("Not a valid font.");
133
    peer = (GdkFontPeer)font.getPeer();
134
 
135
    getGlyphs();
136
    if( flags == Font.LAYOUT_RIGHT_TO_LEFT )
137
      {
138
        // reverse the glyph ordering.
139
        int[] temp = new int[ nGlyphs ];
140
        for(int i = 0; i < nGlyphs; i++)
141
          temp[i] = glyphCodes[nGlyphs - i - 1];
142
        glyphCodes = temp;
143
      }
144
    performDefaultLayout();
145
  }
146
 
147
  /**
148
   * Create a glyphvector from a given set of glyph codes.
149
   */
150
  public FreetypeGlyphVector(Font f, int[] codes, FontRenderContext frc)
151
  {
152
    this.font = f;
153
    this.frc = frc;
154
    if( !(font.getPeer() instanceof GdkFontPeer ) )
155
      throw new IllegalArgumentException("Not a valid font.");
156
    peer = (GdkFontPeer)font.getPeer();
157
 
158
    glyphCodes = new int[ codes.length ];
159
    System.arraycopy(codes, 0, glyphCodes, 0, codes.length);
160
    nGlyphs = glyphCodes.length;
161
 
162
    if (fontSet == null)
163
      {
164
        fontSet = new long[nGlyphs];
165
        Arrays.fill(fontSet, getNativeFontPointer(nGlyphs));
166
      }
167
 
168
    performDefaultLayout();
169
  }
170
 
171
  /**
172
   * Cloning constructor
173
   */
174
  private FreetypeGlyphVector( FreetypeGlyphVector gv )
175
  {
176
    font = gv.font;
177
    peer = gv.peer;
178
    frc = gv.frc;
179
    s = gv.s;
180
    nGlyphs = gv.nGlyphs;
181
    logicalBounds = gv.logicalBounds.getBounds2D();
182
 
183
    if( gv.metricsCache != null )
184
      {
185
        metricsCache = new GlyphMetrics[ nGlyphs ];
186
        System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs);
187
      }
188
 
189
    glyphCodes = new int[ nGlyphs ];
190
    fontSet = new long[nGlyphs];
191
    glyphPositions = new float[(nGlyphs + 1) * 2];
192
    glyphTransforms = new AffineTransform[ nGlyphs ];
193
    Arrays.fill(glyphTransforms, null);
194
 
195
    for(int i = 0; i < nGlyphs; i++ )
196
      {
197
        if (gv.glyphTransforms[i] != null)
198
          glyphTransforms[ i ] = new AffineTransform(gv.glyphTransforms[i]);
199
        glyphCodes[i] = gv.glyphCodes[ i ];
200
      }
201
    System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0,
202
                     glyphPositions.length);
203
    System.arraycopy(gv.glyphCodes, 0, glyphCodes, 0, nGlyphs);
204
    System.arraycopy(gv.fontSet, 0, fontSet, 0, nGlyphs);
205
  }
206
 
207
  public void finalize()
208
  {
209
    dispose(fontSet);
210
  }
211
 
212
  /**
213
   * Create the array of glyph codes.
214
   */
215
  private void getGlyphs()
216
  {
217
    nGlyphs = s.codePointCount( 0, s.length() );
218
    glyphCodes = new int[ nGlyphs ];
219
    fontSet = new long[ nGlyphs ];
220
    int[] codePoints = new int[ nGlyphs ];
221
    int stringIndex = 0;
222
 
223
    for(int i = 0; i < nGlyphs; i++)
224
      {
225
        codePoints[i] = s.codePointAt( stringIndex );
226
        // UTF32 surrogate handling
227
        if( codePoints[i] != (int)s.charAt( stringIndex ) )
228
          stringIndex ++;
229
        stringIndex ++;
230
 
231
        if (Character.isISOControl(codePoints[i]))
232
          {
233
            // Replace with 'hair space'. Should better be 'zero-width space'
234
            // but that doesn't seem to be supported by default font.
235
            codePoints[i] = 8202;
236
          }
237
      }
238
 
239
    getGlyphs( codePoints, glyphCodes, fontSet );
240
  }
241
 
242
  /**
243
   * Returns the glyph code within the font for a given character
244
   */
245
  public native void getGlyphs(int[] codepoints, int[] glyphs, long[] fonts);
246
 
247
  /**
248
   * Returns the kerning of a glyph pair
249
   */
250
  private native void getKerning(int leftGlyph, int rightGlyph, long font,
251
                                 float[] p);
252
 
253
  private native double[] getMetricsNative(int glyphCode, long font);
254
 
255
  private native GeneralPath getGlyphOutlineNative(int glyphIndex, long font);
256
 
257
 
258
  public Object clone()
259
  {
260
    return new FreetypeGlyphVector( this );
261
  }
262
 
263
  /**
264
   * Duh, compares two instances.
265
   */
266
  public boolean equals(GlyphVector gv)
267
  {
268
    if( ! (gv instanceof FreetypeGlyphVector) )
269
      return false;
270
 
271
    return (((FreetypeGlyphVector)gv).font.equals(font) &&
272
            ((FreetypeGlyphVector)gv).frc.equals(frc)
273
            && ((FreetypeGlyphVector)gv).s.equals(s));
274
  }
275
 
276
  /**
277
   * Returns the associated Font
278
   */
279
  public Font getFont()
280
  {
281
    return font;
282
  }
283
 
284
  /**
285
   * Returns the associated FontRenderContext
286
   */
287
  public FontRenderContext getFontRenderContext()
288
  {
289
    return frc;
290
  }
291
 
292
  /**
293
   * Layout the glyphs.
294
   */
295
  public void performDefaultLayout()
296
  {
297
    logicalBounds = null; // invalidate caches.
298
    glyphTransforms = new AffineTransform[nGlyphs];
299
    Arrays.fill(glyphTransforms, null);
300
    glyphPositions = new float[(nGlyphs + 1) * 2];
301
 
302
    GlyphMetrics gm = null;
303
    float x = 0;
304
    float y = 0;
305
    float[] p = {0.0f, 0.0f};
306
    for(int i = 0; i < nGlyphs; i++)
307
      {
308
        gm = getGlyphMetrics( i );
309
        glyphPositions[i*2] = x;
310
        glyphPositions[i*2 + 1] = y;
311
 
312
        x += gm.getAdvanceX();
313
        y += gm.getAdvanceY();
314
 
315
        // Get the kerning only if it's not the last glyph, and the two glyphs are
316
        // using the same font
317
        if (i != nGlyphs-1 && fontSet[i] == fontSet[i+1])
318
          {
319
            getKerning(glyphCodes[i], glyphCodes[i + 1], fontSet[i], p);
320
            x += p[0];
321
            y += p[1];
322
          }
323
      }
324
    glyphPositions[nGlyphs * 2] = x;
325
    glyphPositions[nGlyphs * 2 + 1] = y;
326
 
327
    // Apply any transform that may be in the font's attributes
328
    TransformAttribute ta;
329
    ta = (TransformAttribute)font.getAttributes().get(TextAttribute.TRANSFORM);
330
    if (ta != null)
331
      {
332
        AffineTransform tx = ta.getTransform();
333
 
334
        // Transform glyph positions
335
        tx.transform(glyphPositions, 0, glyphPositions, 0,
336
                     glyphPositions.length / 2);
337
 
338
        // Also store per-glyph scale/shear/rotate (but not translation)
339
        double[] matrix = new double[4];
340
        tx.getMatrix(matrix);
341
        AffineTransform deltaTx = new AffineTransform(matrix);
342
        if (!deltaTx.isIdentity())
343
          Arrays.fill(glyphTransforms, deltaTx);
344
      }
345
  }
346
 
347
  /**
348
   * Returns the code of the glyph at glyphIndex;
349
   */
350
  public int getGlyphCode(int glyphIndex)
351
  {
352
    return glyphCodes[ glyphIndex ];
353
  }
354
 
355
  /**
356
   * Returns multiple glyphcodes.
357
   */
358
  public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
359
                             int[] codeReturn)
360
  {
361
    int[] rval;
362
 
363
    if( codeReturn == null || codeReturn.length < numEntries)
364
      rval = new int[ numEntries ];
365
    else
366
      rval = codeReturn;
367
 
368
    System.arraycopy(glyphCodes, beginGlyphIndex, rval, 0, numEntries);
369
 
370
    return rval;
371
  }
372
 
373
  /**
374
   * Returns pointers to the fonts used in this glyph vector.
375
   *
376
   * The array index matches that of the glyph vector itself.
377
   */
378
  protected long[] getGlyphFonts(int beginGlyphIndex, int numEntries,
379
                                 long[] codeReturn)
380
  {
381
    long[] rval;
382
 
383
    if( codeReturn == null || codeReturn.length < numEntries)
384
      rval = new long[ numEntries ];
385
    else
386
      rval = codeReturn;
387
 
388
    System.arraycopy(fontSet, beginGlyphIndex, rval, 0, numEntries);
389
 
390
    return rval;
391
  }
392
 
393
  public Shape getGlyphLogicalBounds(int glyphIndex)
394
  {
395
    GlyphMetrics gm = getGlyphMetrics( glyphIndex );
396
    if( gm == null )
397
      return null;
398
    Rectangle2D r = gm.getBounds2D();
399
    Point2D p = getGlyphPosition( glyphIndex );
400
 
401
    double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(),
402
                                    p.getY() + r.getY(),
403
                                    p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(),
404
                                    p.getY() + r.getY() + r.getHeight()};
405
 
406
    if (glyphTransforms[glyphIndex] != null)
407
      glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 2);
408
 
409
    return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0],
410
                                  bounds[3] - bounds[1]);
411
  }
412
 
413
  /*
414
   * FIXME: Not all glyph types are supported.
415
   * (The JDK doesn't really seem to do so either)
416
   */
417
  public void setupGlyphMetrics()
418
  {
419
    metricsCache = new GlyphMetrics[ nGlyphs ];
420
 
421
    for(int i = 0; i < nGlyphs; i++)
422
      {
423
        GlyphMetrics gm = (GlyphMetrics)peer.getGlyphMetrics(glyphCodes[i]);
424
        if( gm == null )
425
          {
426
            double[] val = getMetricsNative(glyphCodes[i], fontSet[i]);
427
            if( val == null )
428
              gm = null;
429
            else
430
              {
431
                gm = new GlyphMetrics(true,
432
                                      (float)val[1],
433
                                      (float)val[2],
434
                                      new Rectangle2D.Double(val[3], val[4],
435
                                                             val[5], val[6] ),
436
                                      GlyphMetrics.STANDARD );
437
                peer.putGlyphMetrics( glyphCodes[ i ], gm );
438
              }
439
          }
440
        metricsCache[ i ] = gm;
441
      }
442
  }
443
 
444
  /**
445
   * Returns the metrics of a single glyph.
446
   */
447
  public GlyphMetrics getGlyphMetrics(int glyphIndex)
448
  {
449
    if( metricsCache == null )
450
      setupGlyphMetrics();
451
 
452
    return metricsCache[ glyphIndex ];
453
  }
454
 
455
  /**
456
   * Returns the outline of a single glyph.
457
   *
458
   * Despite what the Sun API says, this method returns the glyph relative to
459
   * the origin of the *entire string*, not each individual glyph.
460
   */
461
  public Shape getGlyphOutline(int glyphIndex)
462
  {
463
    GeneralPath gp = getGlyphOutlineNative(glyphCodes[glyphIndex],
464
                                           fontSet[glyphIndex]);
465
 
466
    AffineTransform tx = AffineTransform.getTranslateInstance(glyphPositions[glyphIndex*2],
467
                                                              glyphPositions[glyphIndex*2+1]);
468
    if (glyphTransforms[glyphIndex] != null)
469
      tx.concatenate( glyphTransforms[glyphIndex]);
470
 
471
    gp.transform(tx);
472
    return gp;
473
  }
474
 
475
  /**
476
   * Returns the position of a single glyph.
477
   */
478
  public Point2D getGlyphPosition(int glyphIndex)
479
  {
480
    return new Point2D.Float(glyphPositions[glyphIndex*2],
481
                             glyphPositions[glyphIndex*2 + 1]);
482
  }
483
 
484
  /**
485
   * Returns the positions of multiple glyphs.
486
   */
487
  public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
488
                                   float[] positionReturn)
489
  {
490
    if (positionReturn == null || positionReturn.length < (numEntries * 2))
491
      positionReturn = new float[numEntries*2];
492
 
493
    System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0,
494
                     numEntries*2);
495
    return positionReturn;
496
  }
497
 
498
  /**
499
   * Returns the transform of a glyph.
500
   */
501
  public AffineTransform getGlyphTransform(int glyphIndex)
502
  {
503
    return glyphTransforms[glyphIndex];
504
  }
505
 
506
  /**
507
   * Checks whether any transform has been set on any glyphs.
508
   */
509
  protected boolean hasTransforms()
510
  {
511
    for (int i = 0; i < glyphTransforms.length; i++)
512
      if (glyphTransforms[i] != null)
513
        return true;
514
 
515
    return false;
516
  }
517
 
518
  /**
519
   * Returns the visual bounds of a glyph
520
   * May be off by a pixel or two due to hinting/rasterization.
521
   */
522
  public Shape getGlyphVisualBounds(int glyphIndex)
523
  {
524
    return getGlyphOutline( glyphIndex ).getBounds2D();
525
  }
526
 
527
  /**
528
   * Return the logical bounds of the whole thing.
529
   */
530
  public Rectangle2D getLogicalBounds()
531
  {
532
    if( nGlyphs == 0 )
533
      return new Rectangle2D.Double(0, 0, 0, 0);
534
    if( logicalBounds != null )
535
      return logicalBounds;
536
 
537
    Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 );
538
    for( int i = 1; i < nGlyphs; i++ )
539
      {
540
        Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
541
 
542
        rect = rect.createUnion( r2 );
543
      }
544
 
545
    logicalBounds = rect;
546
    return rect;
547
  }
548
 
549
  /**
550
   * Returns the number of glyphs.
551
   */
552
  public int getNumGlyphs()
553
  {
554
    return glyphCodes.length;
555
  }
556
 
557
  /**
558
   * Returns the outline of the entire GlyphVector.
559
   */
560
  public Shape getOutline()
561
  {
562
    GeneralPath path = new GeneralPath();
563
    for( int i = 0; i < getNumGlyphs(); i++ )
564
      path.append(getGlyphOutline(i), false);
565
    return path;
566
  }
567
 
568
  /**
569
   * TODO:
570
   * FreeType does not currently have an API for the JSTF table. We should
571
   * probably get the table ourselves from FT and pass it to some parser
572
   * which the native font peers will need.
573
   */
574
  public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex)
575
  {
576
    return null;
577
  }
578
 
579
  /**
580
   * Returns the outline of the entire vector, drawn at (x,y).
581
   */
582
  public Shape getOutline(float x, float y)
583
  {
584
    AffineTransform tx = AffineTransform.getTranslateInstance( x, y );
585
    GeneralPath gp = (GeneralPath)getOutline();
586
    gp.transform( tx );
587
    return gp;
588
  }
589
 
590
  /**
591
   * Returns the visual bounds of the entire GlyphVector.
592
   * May be off by a pixel or two due to hinting/rasterization.
593
   */
594
  public Rectangle2D getVisualBounds()
595
  {
596
    return getOutline().getBounds2D();
597
  }
598
 
599
  /**
600
   * Sets the position of a glyph.
601
   */
602
  public void setGlyphPosition(int glyphIndex, Point2D newPos)
603
  {
604
    glyphPositions[glyphIndex*2] = (float)(newPos.getX());
605
    glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY());
606
    logicalBounds = null;
607
  }
608
 
609
  /**
610
   * Sets the transform of a single glyph.
611
   */
612
  public void setGlyphTransform(int glyphIndex, AffineTransform newTX)
613
  {
614
    // The identity transform should never be in the glyphTransforms array;
615
    // using and checking for nulls can be much faster.
616
    if (newTX != null && newTX.isIdentity())
617
      newTX = null;
618
 
619
    // If the old and new transforms are identical, bail
620
    if (glyphTransforms[glyphIndex] == null && newTX == null)
621
      return;
622
 
623
    if (newTX != null && newTX.equals(glyphTransforms[glyphIndex]))
624
      return;
625
 
626
    // Invalidate bounds cache and set new transform
627
    logicalBounds = null;
628
    glyphTransforms[glyphIndex] = newTX;
629
  }
630
}

powered by: WebSVN 2.1.0

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