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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* GNUGlyphVector.java -- The GNU implementation of GlyphVector.
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.font;
39
 
40
import gnu.java.awt.java2d.ShapeWrapper;
41
 
42
import java.awt.Font;
43
import java.awt.font.FontRenderContext;
44
import java.awt.font.GlyphMetrics;
45
import java.awt.font.GlyphJustificationInfo;
46
import java.awt.font.GlyphVector;
47
 
48
import java.awt.Shape;
49
import java.awt.geom.AffineTransform;
50
import java.awt.geom.GeneralPath;
51
import java.awt.geom.Point2D;
52
import java.awt.geom.Rectangle2D;
53
 
54
 
55
/**
56
 * The GNU implementation of the abstract GlyphVector class, which
57
 * uses the services provided by a FontDelegate for its functionality.
58
 *
59
 * @author Sascha Brawer (brawer@dandelis.ch)
60
 */
61
public class GNUGlyphVector
62
  extends GlyphVector
63
{
64
  private FontDelegate fontDelegate;
65
  private Font font;
66
  private FontRenderContext renderContext;
67
  private int[] glyphs;
68
  private float fontSize;
69
  private AffineTransform transform;
70
  private boolean valid;
71
 
72
 
73
  /**
74
   * The position of each glyph. The horizontal position of the
75
   * <code>i</code>-th glyph is at <code>pos[i * 2]</code>, its
76
   * vertical position at <code>pos[i * 2 + 1]</code>. The total
77
   * advance width of the entire vector is stored at
78
   * <code>pos[numGlyphs]</code>, the total advance height at
79
   * <code>pos[numGlyphs + 1]</code>.
80
   */
81
  private float[] pos;
82
 
83
 
84
  private AffineTransform[] transforms;
85
  private int layoutFlags;
86
 
87
  /**
88
   * The cached non-transformed outline of this glyph vector.
89
   */
90
  private Shape cleanOutline;
91
 
92
  /**
93
   * Constructs a new GNUGlyphVector.
94
   *
95
   * @param fontDelegate the FontDelegate that creates this vector.
96
   *
97
   * @param font the Font that this GlyphVector will return for {@link
98
   * #getFont()}. That object is also used to determine the point
99
   * size, which affects the affine transformation used by the font
100
   * scaler.
101
   *
102
   * @param renderContext an object with parameters for font
103
   * rendering, such as whether anti-aliasing is enabled.
104
   *
105
   * @param glyphs the glyphs in this vector.
106
   */
107
  public GNUGlyphVector(FontDelegate fontDelegate,
108
                        Font font,
109
                        FontRenderContext renderContext,
110
                        int[] glyphs)
111
  {
112
    this.fontDelegate = fontDelegate;
113
    this.font = font;
114
    this.renderContext = renderContext;
115
    this.glyphs = glyphs;
116
 
117
    fontSize = font.getSize2D();
118
    transform = font.getTransform(); // returns a modifiable copy
119
    //transform.concatenate(renderContext.getTransform());
120
  }
121
 
122
 
123
 
124
  /**
125
   * Returns the font of the glyphs in this GlyphVector.
126
   */
127
  public Font getFont()
128
  {
129
    return font;
130
  }
131
 
132
 
133
  /**
134
   * Returns the FontRenderContext that is used to calculate the
135
   * extent and position of the glyphs.
136
   */
137
  public FontRenderContext getFontRenderContext()
138
  {
139
    return renderContext;
140
  }
141
 
142
 
143
  /**
144
   * Moves each glyph in the vector to its default position.
145
   */
146
  public void performDefaultLayout()
147
  {
148
    float x, y, advanceWidth, advanceHeight;
149
    int i, p;
150
    AffineTransform tx;
151
    Point2D.Float advance = new Point2D.Float();
152
 
153
    pos = new float[(glyphs.length + 1) * 2];
154
    x = y = 0.0f;
155
    p = 0;
156
    for (i = p = 0; i < glyphs.length; i++)
157
    {
158
      p += 2;
159
 
160
      if ((transforms == null) || (tx = transforms[i]) == null)
161
        tx = this.transform;
162
      else
163
      {
164
        tx = new AffineTransform(tx);
165
        tx.concatenate(this.transform);
166
      }
167
 
168
      fontDelegate.getAdvance(glyphs[i], fontSize, tx,
169
                              renderContext.isAntiAliased(),
170
                              renderContext.usesFractionalMetrics(),
171
                              /* horizontal */ true,
172
                              advance);
173
      // FIXME: We shouldn't round here, but instead hint the metrics
174
      // correctly.
175
      pos[p] = x += Math.round(advance.x);
176
      pos[p + 1] = y += advance.y;
177
    }
178
    valid = true;
179
  }
180
 
181
 
182
  /**
183
   * Determines the number of glyphs in this GlyphVector.
184
   */
185
  public int getNumGlyphs()
186
  {
187
    return glyphs.length;
188
  }
189
 
190
 
191
  /**
192
   * Determines the glyph number by index in this vector.
193
   * Glyph numbers are specific to each font, so two fonts
194
   * will likely assign different numbers to the same glyph.
195
   *
196
   * @param glyphIndex the index of the glyph whose glyph number is to
197
   * be retrieved.
198
   *
199
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code>
200
   * is not in the range <code[0 .. getNumGlyphs() - 1]</code>.
201
   */
202
  public int getGlyphCode(int glyphIndex)
203
  {
204
    /* The exception is thrown automatically if the index is out
205
     * of the valid bounds.
206
     */
207
    return glyphs[glyphIndex];
208
  }
209
 
210
 
211
  /**
212
   * Returns a slice of this GlyphVector.
213
   *
214
   * @param firstGlyphIndex the index of the first glyph in the
215
   * returned slice.
216
   *
217
   * @param numEntries the size of the returned slice.
218
   *
219
   * @param outCodes a pre-allocated array for storing the slice,
220
   * or <code>null</code> to cause allocation of a new array.
221
   *
222
   * @return a slice of this GlyphVector. If <code>outCodes</code>
223
   * is <code>null</code>, the slice will be stored into a freshly
224
   * allocated array; otherwise, the result will be stored into
225
   * <code>outCodes</code>.
226
   */
227
  public int[] getGlyphCodes(int firstGlyphIndex,
228
                             int numEntries,
229
                             int[] outCodes)
230
  {
231
    if (numEntries < 0)
232
      throw new IllegalArgumentException();
233
    if (outCodes == null)
234
      outCodes = new int[numEntries];
235
    System.arraycopy(glyphs, firstGlyphIndex, outCodes, 0, numEntries);
236
    return outCodes;
237
  }
238
 
239
 
240
  public Rectangle2D getLogicalBounds()
241
  {
242
    float ascent, descent;
243
 
244
    validate();
245
 
246
    return new Rectangle2D.Float(0, 0,
247
                                 pos[pos.length - 2],
248
                                 getAscent() - getDescent());
249
  }
250
 
251
 
252
  public Rectangle2D getVisualBounds()
253
  {
254
    validate();
255
 
256
    // FIXME: Not yet implemented.
257
    return getLogicalBounds();
258
  }
259
 
260
 
261
  /**
262
   * Returns the shape of this GlyphVector.
263
   */
264
  public Shape getOutline()
265
  {
266
    return getOutline(0.0f, 0.0f);
267
  }
268
 
269
 
270
  /**
271
   * Returns the shape of this GlyphVector, translated to the
272
   * specified position.
273
   *
274
   * @param x the horizontal position for rendering this vector.
275
   * @param y the vertical position for rendering this vector.
276
   */
277
  public Shape getOutline(float x, float y)
278
  {
279
    validate();
280
 
281
    Shape outline;
282
    if (cleanOutline == null)
283
      {
284
        GeneralPath path = new GeneralPath();
285
        int len = glyphs.length;
286
        for (int i = 0; i < len; i++)
287
          {
288
            GeneralPath p = new GeneralPath(getGlyphOutline(i));
289
            path.append(p, false);
290
          }
291
        // Protect the cached instance from beeing modified by application
292
        // code.
293
        cleanOutline = new ShapeWrapper(path);
294
        outline = cleanOutline;
295
      }
296
    else
297
      {
298
        outline = cleanOutline;
299
      }
300
    if (x != 0 || y != 0)
301
      {
302
        GeneralPath path = new GeneralPath(outline);
303
        AffineTransform t = new AffineTransform();
304
        t.translate(x, y);
305
        path.transform(t);
306
        outline = path;
307
      }
308
    return outline;
309
  }
310
 
311
  public Shape getOutline(float x, float y, int type)
312
  {
313
    validate();
314
 
315
    GeneralPath outline = new GeneralPath();
316
    int len = glyphs.length;
317
    for (int i = 0; i < len; i++)
318
      {
319
        GeneralPath p = new GeneralPath(getGlyphOutline(i, type));
320
        outline.append(p, false);
321
      }
322
    AffineTransform t = new AffineTransform();
323
    t.translate(x, y);
324
    outline.transform(t);
325
    return outline;
326
  }
327
 
328
  /**
329
   * Determines the shape of the specified glyph.
330
   *
331
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
332
   * not in the range <code[0 .. getNumGlyphs()]</code>.
333
   */
334
  public Shape getGlyphOutline(int glyphIndex)
335
  {
336
    AffineTransform tx, glyphTx;
337
    GeneralPath path;
338
 
339
    validate();
340
 
341
    if ((transforms != null)
342
        && ((glyphTx = transforms[glyphIndex]) != null))
343
    {
344
      tx =  new AffineTransform(transform);
345
      tx.concatenate(glyphTx);
346
    }
347
    else
348
      tx = transform;
349
 
350
    path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx,
351
                                        renderContext.isAntiAliased(),
352
                                        renderContext.usesFractionalMetrics(),
353
                                        FontDelegate.FLAG_FITTED);
354
 
355
    tx = new AffineTransform();
356
    tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]);
357
    path.transform(tx);
358
    return path;
359
  }
360
 
361
  public Shape getGlyphOutline(int glyphIndex, int type)
362
  {
363
    AffineTransform tx, glyphTx;
364
    GeneralPath path;
365
 
366
    validate();
367
 
368
    if ((transforms != null)
369
        && ((glyphTx = transforms[glyphIndex]) != null))
370
    {
371
      tx =  new AffineTransform(transform);
372
      tx.concatenate(glyphTx);
373
    }
374
    else
375
      tx = transform;
376
 
377
    path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx,
378
                                        renderContext.isAntiAliased(),
379
                                        renderContext.usesFractionalMetrics(),
380
                                        type);
381
 
382
    tx = new AffineTransform();
383
    tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]);
384
    path.transform(tx);
385
    return path;
386
  }
387
 
388
  /**
389
   * Determines the position of the specified glyph, or the
390
   * total advance width and height of the vector.
391
   *
392
   * @param glyphIndex the index of the glyph in question.
393
   * If this value equals <code>getNumGlyphs()</code>, the
394
   * position <i>after</i> the last glyph will be returned,
395
   * which is the total advance width and height of the vector.
396
   *
397
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
398
   * not in the range <code[0 .. getNumGlyphs()]</code>.
399
   */
400
  public Point2D getGlyphPosition(int glyphIndex)
401
  {
402
    validate();
403
    return new Point2D.Float(pos[glyphIndex * 2],
404
                             pos[glyphIndex * 2 + 1]);
405
  }
406
 
407
 
408
  /**
409
   * Moves the specified glyph to a new position, or changes the
410
   * advance width and height of the entire glyph vector.
411
   *
412
   * <p>Note that the position of an individual glyph may also
413
   * affected by its affine transformation.
414
   *
415
   * @param glyphIndex the index of the moved glyph. If
416
   * <code>glyphIndex</code> equals the total number of glyphs in this
417
   * vector, the advance width and height of the vector is changed.
418
   *
419
   * @param position the new position of the glyph.
420
   *
421
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
422
   * not in the range <code[0 .. getNumGlyphs()]</code>.
423
   */
424
  public void setGlyphPosition(int glyphIndex, Point2D position)
425
  {
426
    validate();
427
    pos[glyphIndex * 2] = (float) position.getX();
428
    pos[glyphIndex * 2 + 1] = (float) position.getY();
429
  }
430
 
431
 
432
  /**
433
   * Returns the affine transformation that is applied to the
434
   * glyph at the specified index.
435
   *
436
   * @param glyphIndex the index of the glyph whose transformation
437
   * is to be retrieved.
438
   *
439
   * @return an affine transformation, or <code>null</code>
440
   * for the identity transformation.
441
   *
442
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
443
   * not in the range <code[0 .. getNumGlyphs() - 1]</code>.
444
   */
445
  public AffineTransform getGlyphTransform(int glyphIndex)
446
  {
447
    if (transforms == null)
448
      return null;
449
    else
450
      return transforms[glyphIndex];
451
  }
452
 
453
 
454
  /**
455
   * Applies an affine transformation to the glyph at the specified
456
   * index.
457
   *
458
   * @param glyphIndex the index of the glyph to which the
459
   * transformation is applied.
460
   *
461
   * @param transform the affine transformation for the glyph, or
462
   * <code>null</code> for an identity transformation.
463
   */
464
  public void setGlyphTransform(int glyphIndex,
465
                                AffineTransform transform)
466
  {
467
    if (transforms == null)
468
      transforms = new AffineTransform[glyphs.length];
469
    transforms[glyphIndex] = transform;
470
 
471
    /* If the GlyphVector has only a transform for a single glyph, and
472
     * the caller clears its transform, the FLAG_HAS_TRANSFORMS bit
473
     * should be cleared in layoutFlags.  However, this would require
474
     * that we keep track of the number of transformed glyphs, or that
475
     * we count them when a transform is cleared. This would
476
     * complicate the code quite a bit. Note that the only drawback of
477
     * wrongly setting FLAG_HAS_TRANSFORMS is that a slower code path
478
     * might be taken for rendering the vector. Right now, we never
479
     * really look at the flag, so it does not make any difference.
480
     */
481
    if (transform != null)
482
      layoutFlags |= FLAG_HAS_TRANSFORMS;
483
    valid = false;
484
  }
485
 
486
 
487
  /**
488
   * Returns flags that can be used for optimizing the rendering
489
   * of this GlyphVector.
490
   *
491
   * @return a bit mask with the applicable flags set.
492
   *
493
   * @since 1.4
494
   *
495
   * @see GlyphVector#FLAG_HAS_POSITION_ADJUSTMENTS
496
   * @see GlyphVector#FLAG_HAS_TRANSFORMS
497
   * @see GlyphVector#FLAG_RUN_RTL
498
   * @see GlyphVector#FLAG_COMPLEX_GLYPHS
499
   * @see GlyphVector#FLAG_MASK
500
   */
501
  public int getLayoutFlags()
502
  {
503
    return layoutFlags;
504
  }
505
 
506
 
507
  /**
508
   * Returns the positions of a range of glyphs in this vector.
509
   *
510
   * @param firstGlyphIndex the index of the first glyph whose
511
   * position is retrieved.
512
   *
513
   * @param numGlyphs the number of glyphs whose positions
514
   * are retrieved.
515
   *
516
   * @param outPositions an array for storing the results
517
   * (the length must be at least twice <code>numGlyphs</code>),
518
   * or <code>null</code> for freshly allocating an array.
519
   *
520
   * @return an array with the glyph positions. The horizontal
521
   * position of the <code>i</code>-th glyph is at index <code>2 *
522
   * i</code>, the vertical position at index <code>2 * i + 1</code>.
523
   *
524
   * @throws IllegalArgumentException if <code>numGlyphs</code>
525
   * is less than zero.
526
   *
527
   * @throws IndexOutOfBoundsException if either
528
   * <code>firstGlyphIndex</code> or <code>(firstGlyphIndex +
529
   * numGlyphs)</code> is not in the range <code>[0 .. getNumGlyphs() -
530
   * 1]</code>.
531
   */
532
  public float[] getGlyphPositions(int firstGlyphIndex,
533
                                   int numGlyphs,
534
                                   float[] outPositions)
535
  {
536
    if (numGlyphs < 0)
537
      throw new IllegalArgumentException();
538
 
539
    validate();
540
    if (outPositions == null)
541
      outPositions = new float[numGlyphs * 2];
542
 
543
    System.arraycopy(/*src */ pos, /* srcStart */ firstGlyphIndex * 2,
544
                     /* dest */ outPositions, /* destStart */ 0,
545
                     /* length */ numGlyphs * 2);
546
    return outPositions;
547
  }
548
 
549
 
550
  private float getAscent()
551
  {
552
    return fontDelegate.getAscent(fontSize, transform,
553
                                  renderContext.isAntiAliased(),
554
                                  renderContext.usesFractionalMetrics(),
555
                                  /* horizontal */ true);
556
  }
557
 
558
 
559
  private float getDescent()
560
  {
561
    return fontDelegate.getDescent(fontSize, transform,
562
                                   renderContext.isAntiAliased(),
563
                                   renderContext.usesFractionalMetrics(),
564
                                   /* horizontal */ true);
565
  }
566
 
567
 
568
  public Shape getGlyphLogicalBounds(int glyphIndex)
569
  {
570
    float x, y, ascent;
571
 
572
    validate();
573
    ascent = getAscent();
574
    x = pos[glyphIndex * 2];
575
    y = pos[glyphIndex * 2 + 1];
576
 
577
    return new Rectangle2D.Float(x, y - ascent,
578
                                 pos[(glyphIndex + 1) * 2] - x,
579
                                 ascent - getDescent());
580
  }
581
 
582
 
583
  public Shape getGlyphVisualBounds(int glyphIndex)
584
  {
585
    return getGlyphOutline(glyphIndex).getBounds2D();
586
  }
587
 
588
 
589
  /**
590
   * Determines the metrics of the glyph at the specified index.
591
   *
592
   * @param glyphIndex the index of the glyph whose metrics is to be
593
   * retrieved.
594
   *
595
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
596
   * not in the range <code[0 .. getNumGlyphs() - 1]</code>.
597
   */
598
  public GlyphMetrics getGlyphMetrics(int glyphIndex)
599
  {
600
    // FIXME: Not yet implemented.
601
    throw new UnsupportedOperationException();
602
  }
603
 
604
 
605
  /**
606
   * Determines the justification information for the glyph at the
607
   * specified index.
608
   *
609
   * @param glyphIndex the index of the glyph whose justification
610
   * information is to be retrieved.
611
   *
612
   * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
613
   * not in the range <code[0 .. getNumGlyphs() - 1]</code>.
614
   */
615
  public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex)
616
  {
617
    // FIXME: Not yet implemented.
618
    throw new UnsupportedOperationException();
619
  }
620
 
621
 
622
  /**
623
   * Determines whether another GlyphVector is for the same font and
624
   * rendering context, uses the same glyphs and positions them to the
625
   * same location.
626
   *
627
   * @param other the GlyphVector to compare with.
628
   *
629
   * @return <code>true</code> if the two vectors are equal,
630
   * <code>false</code> otherwise.
631
   */
632
  public boolean equals(GlyphVector other)
633
  {
634
    GNUGlyphVector o;
635
    if (!(other instanceof GNUGlyphVector))
636
      return false;
637
 
638
    o = (GNUGlyphVector) other;
639
    if ((this.font != o.font)
640
        || (this.fontDelegate != o.fontDelegate)
641
        || (this.renderContext != o.renderContext)
642
        || (this.glyphs.length != o.glyphs.length))
643
      return false;
644
 
645
    for (int i = 0; i < glyphs.length; i++)
646
      if (this.glyphs[i] != o.glyphs[i])
647
        return false;
648
 
649
    validate();
650
    o.validate();
651
    for (int i = 0; i < pos.length; i++)
652
      if (this.pos[i] != o.pos[i])
653
        return false;
654
 
655
    return true;
656
  }
657
 
658
  private void validate()
659
  {
660
    if (!valid)
661
      performDefaultLayout();
662
  }
663
}

powered by: WebSVN 2.1.0

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