KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > gvt > font > SVGGVTGlyphVector


1 /*
2
3    Copyright 2001-2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.gvt.font;
19
20 import java.awt.Graphics2D JavaDoc;
21 import java.awt.Shape JavaDoc;
22 import java.awt.font.FontRenderContext JavaDoc;
23 import java.awt.font.GlyphJustificationInfo JavaDoc;
24 import java.awt.geom.AffineTransform JavaDoc;
25 import java.awt.geom.GeneralPath JavaDoc;
26 import java.awt.geom.Point2D JavaDoc;
27 import java.awt.geom.Rectangle2D JavaDoc;
28 import java.text.AttributedCharacterIterator JavaDoc;
29
30 import org.apache.batik.gvt.text.ArabicTextHandler;
31 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
32 import org.apache.batik.gvt.text.TextPaintInfo;
33
34 /**
35  * A GVTGlyphVector class for SVG fonts.
36  *
37  * @author <a HREF="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
38  * @version $Id: SVGGVTGlyphVector.java,v 1.22 2005/03/18 00:38:12 deweese Exp $
39  */

40 public final class SVGGVTGlyphVector implements GVTGlyphVector {
41
42     public static final AttributedCharacterIterator.Attribute JavaDoc PAINT_INFO
43         = GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO;
44
45     private GVTFont font;
46     private Glyph[] glyphs;
47     private FontRenderContext JavaDoc frc;
48     private GeneralPath JavaDoc outline;
49     private Rectangle2D JavaDoc logicalBounds;
50     private Rectangle2D JavaDoc bounds2D;
51     private Shape JavaDoc[] glyphLogicalBounds;
52     private boolean[] glyphVisible;
53     private Point2D JavaDoc endPos;
54     private TextPaintInfo cacheTPI;
55
56     /**
57      * Constructs an SVGGVTGlyphVector.
58      *
59      * @param font The font that is creating this glyph vector.
60      * @param glyphs An array containing the glyphs that form the basis for this
61      * glyph vector.
62      * @param frc The current font render context.
63      */

64     public SVGGVTGlyphVector(GVTFont font, Glyph[] glyphs,
65                              FontRenderContext JavaDoc frc) {
66         this.font = font;
67         this.glyphs = glyphs;
68         this.frc = frc;
69         outline = null;
70         bounds2D = null;
71         logicalBounds = null;
72         glyphLogicalBounds = new Shape JavaDoc[glyphs.length];
73         glyphVisible = new boolean[glyphs.length];
74         for (int i = 0; i < glyphs.length; i++) {
75             glyphVisible[i] = true;
76         }
77
78         endPos = glyphs[glyphs.length-1].getPosition();
79         endPos = new Point2D.Float JavaDoc
80             ((float)(endPos.getX()+glyphs[glyphs.length-1].getHorizAdvX()),
81              (float)endPos.getY());
82     }
83
84     /**
85      * Returns the Font associated with this GlyphVector.
86      */

87     public GVTFont getFont() {
88         return font;
89     }
90
91     /**
92      * Returns the FontRenderContext associated with this GlyphVector.
93      */

94     public FontRenderContext JavaDoc getFontRenderContext() {
95         return frc;
96     }
97
98     /**
99      * Returns the glyphcode of the specified glyph.
100      */

101     public int getGlyphCode(int glyphIndex) throws IndexOutOfBoundsException JavaDoc {
102         if (glyphIndex < 0 || glyphIndex > (glyphs.length-1)) {
103             throw new IndexOutOfBoundsException JavaDoc("glyphIndex " + glyphIndex
104                       + " is out of bounds, should be between 0 and "
105                       + (glyphs.length-1));
106         }
107         return glyphs[glyphIndex].getGlyphCode();
108     }
109
110     /**
111      * Returns an array of glyphcodes for the specified glyphs.
112      */

113     public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
114                                int[] codeReturn)
115                                throws IndexOutOfBoundsException JavaDoc,
116                                        IllegalArgumentException JavaDoc {
117         if (numEntries < 0) {
118             throw new IllegalArgumentException JavaDoc("numEntries argument value, "
119                       + numEntries + ", is illegal. It must be > 0.");
120         }
121         if (beginGlyphIndex < 0) {
122             throw new IndexOutOfBoundsException JavaDoc("beginGlyphIndex " + beginGlyphIndex
123                       + " is out of bounds, should be between 0 and "
124                       + (glyphs.length-1));
125         }
126         if ((beginGlyphIndex+numEntries) > glyphs.length) {
127              throw new IndexOutOfBoundsException JavaDoc("beginGlyphIndex + numEntries ("
128                        + beginGlyphIndex + "+" + numEntries
129                        + ") exceeds the number of glpyhs in this GlyphVector");
130         }
131         if (codeReturn == null) {
132             codeReturn = new int[numEntries];
133         }
134         for (int i = beginGlyphIndex; i < (beginGlyphIndex+numEntries); i++) {
135             codeReturn[i-beginGlyphIndex] = glyphs[i].getGlyphCode();
136         }
137         return codeReturn;
138     }
139
140     /**
141      * Returns the justification information for the glyph at the specified
142      * index into this GlyphVector.
143      */

144     public GlyphJustificationInfo JavaDoc getGlyphJustificationInfo(int glyphIndex) {
145         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
146             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
147             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
148         }
149         return null;
150     }
151
152      /**
153      * Returns the logical bounds of the specified glyph within this
154      * GlyphVector.
155      */

156     public Shape JavaDoc getGlyphLogicalBounds(int glyphIndex) {
157         if (glyphLogicalBounds[glyphIndex] == null && glyphVisible[glyphIndex]) {
158             computeGlyphLogicalBounds();
159         }
160         return glyphLogicalBounds[glyphIndex];
161     }
162
163
164     private void computeGlyphLogicalBounds() {
165
166         float ascent = 0;
167         float descent = 0;
168         if (font != null) {
169             // font will only be null if this glyph vector is for an altGlyph
170
GVTLineMetrics lineMetrics = font.getLineMetrics("By", frc);
171             ascent = lineMetrics.getAscent();
172             descent = lineMetrics.getDescent();
173             if (descent < 0) {
174                 // make descent a positive value
175
descent = -descent;
176             }
177         }
178
179         if (ascent == 0) {
180             float maxAscent = 0;
181             float maxDescent = 0;
182             for (int i = 0; i < getNumGlyphs(); i++) {
183                 if (!glyphVisible[i]) continue;
184                 GVTGlyphMetrics glyphMetrics = getGlyphMetrics(i);
185                 Rectangle2D JavaDoc glyphBounds = glyphMetrics.getBounds2D();
186                 ascent = (float)(-glyphBounds.getMinY());
187                 descent = (float)(glyphBounds.getHeight()-ascent);
188                 if (ascent > maxAscent) maxAscent = ascent;
189                 if (descent > maxDescent) maxDescent = descent;
190             }
191             ascent = maxAscent;
192             descent = maxDescent;
193         }
194
195         Shape JavaDoc[] tempLogicalBounds = new Shape JavaDoc[getNumGlyphs()];
196         boolean[] rotated = new boolean[getNumGlyphs()];
197
198         double maxWidth = -1;
199         double maxHeight = -1;
200
201         for (int i = 0; i < getNumGlyphs(); i++) {
202
203             if (!glyphVisible[i]) {
204                 // the glyph is not drawn
205
tempLogicalBounds[i] = null;
206                 continue;
207             }
208
209             AffineTransform JavaDoc glyphTransform = getGlyphTransform(i);
210             GVTGlyphMetrics glyphMetrics = getGlyphMetrics(i);
211             Rectangle2D JavaDoc glyphBounds = new Rectangle2D.Double JavaDoc
212                 (0, -ascent, glyphMetrics.getHorizontalAdvance(),
213                  ascent+descent);
214
215             if (glyphBounds.isEmpty()) {
216                 // can't tell if rotated or not, make it
217
// the same as the previous glyph, if we have one...
218
if (i > 0) {
219                     rotated[i] = rotated[i-1];
220                 } else {
221                     rotated [i] = true;
222                 }
223             } else {
224                 // get three corner points so we can determine
225
// whether the glyph is rotated
226
Point2D JavaDoc p1 = new Point2D.Double JavaDoc(glyphBounds.getMinX(),
227                                                 glyphBounds.getMinY());
228                 Point2D JavaDoc p2 = new Point2D.Double JavaDoc(glyphBounds.getMaxX(),
229                                                 glyphBounds.getMinY());
230                 Point2D JavaDoc p3 = new Point2D.Double JavaDoc(glyphBounds.getMinX(),
231                                                 glyphBounds.getMaxY());
232                 Point2D JavaDoc gpos = getGlyphPosition(i);
233                 AffineTransform JavaDoc tr = AffineTransform.getTranslateInstance
234                     (gpos.getX(), gpos.getY());
235                     
236                 if (glyphTransform != null)
237                     tr.concatenate(glyphTransform);
238
239                 tempLogicalBounds[i] =
240                     tr.createTransformedShape(glyphBounds);
241                     
242                 Point2D JavaDoc tp1 = new Point2D.Double JavaDoc();
243                 Point2D JavaDoc tp2 = new Point2D.Double JavaDoc();
244                 Point2D JavaDoc tp3 = new Point2D.Double JavaDoc();
245                 tr.transform(p1, tp1);
246                 tr.transform(p2, tp2);
247                 tr.transform(p3, tp3);
248                 double tdx12 = tp1.getX()-tp2.getX();
249                 double tdx13 = tp1.getX()-tp3.getX();
250                 double tdy12 = tp1.getY()-tp2.getY();
251                 double tdy13 = tp1.getY()-tp3.getY();
252
253                 if ((Math.abs(tdx12) < 0.001) &&
254                     (Math.abs(tdy13) < 0.001)) {
255                     // If these are both zero then it is axially aligned
256
// on it's "side"...
257
rotated[i] = false;
258                     double dx13 = p1.getX()-p3.getX();
259                     double dy12 = p1.getY()-p2.getY();
260                         
261                 } else if ((Math.abs(tdx13) < 0.001) &&
262                            (Math.abs(tdy12) < 0.001)) {
263                     // If these are both zero then it is axially aligned
264
// vertically.
265
rotated[i] = false;
266                     double dx12 = p1.getX()-p2.getX();
267                     double dy13 = p1.getY()-p3.getY();
268                 } else {
269                     rotated [i] = true;
270                 }
271                     
272                 Rectangle2D JavaDoc rectBounds;
273                 rectBounds = tempLogicalBounds[i].getBounds2D();
274                 if (rectBounds.getWidth() > maxWidth)
275                     maxWidth = rectBounds.getWidth();
276                 if (rectBounds.getHeight() > maxHeight)
277                     maxHeight = rectBounds.getHeight();
278             }
279         }
280
281         // if appropriate, join adjacent glyph logical bounds
282
GeneralPath JavaDoc logicalBoundsPath = new GeneralPath JavaDoc();
283         for (int i = 0; i < getNumGlyphs(); i++) {
284             if (tempLogicalBounds[i] != null) {
285                 logicalBoundsPath.append(tempLogicalBounds[i], false);
286             }
287         }
288         Rectangle2D JavaDoc fullBounds = logicalBoundsPath.getBounds2D();
289
290         if (fullBounds.getHeight() < maxHeight*1.5) {
291             // make all glyphs tops and bottoms the same as the full bounds
292
for (int i = 0; i < getNumGlyphs(); i++) {
293                 // first make sure that the glyph logical bounds are
294
// not rotated
295
if (rotated[i]) continue;
296                 if (tempLogicalBounds[i] == null) continue;
297
298                 Rectangle2D JavaDoc glyphBounds = tempLogicalBounds[i].getBounds2D();
299
300                 double x = glyphBounds.getMinX();
301                 double width = glyphBounds.getWidth();
302
303                 if ((i < getNumGlyphs()-1) &&
304                     (tempLogicalBounds[i+1] != null)) {
305                     // make this glyph extend to the start of the next one
306
Rectangle2D JavaDoc nextGlyphBounds =
307                         tempLogicalBounds[i+1].getBounds2D();
308                     // make this glyph extend to the start of the next one
309
Rectangle2D JavaDoc ngb = tempLogicalBounds[i+1].getBounds2D();
310
311                     if (ngb.getX() > x) {
312                         double nw = ngb.getX() - x;
313                         if ((nw < width*1.15) && (nw > width*.85)) {
314                             double delta = (nw-width)*.5;
315                             width += delta;
316                             ngb.setRect(ngb.getX()-delta, ngb.getY(),
317                                         ngb.getWidth()+delta, ngb.getHeight());
318                         }
319                     }
320                 }
321                 tempLogicalBounds[i] = new Rectangle2D.Double JavaDoc
322                     (x, fullBounds.getMinY(),
323                      width, fullBounds.getHeight());
324             }
325         } else if (fullBounds.getWidth() < maxWidth*1.5) {
326             // make all glyphs left and right edges the same as the full bounds
327
for (int i = 0; i < getNumGlyphs(); i++) {
328                 // first make sure that the glyph logical bounds are
329
// not rotated
330
if (rotated[i]) continue;
331                 if (tempLogicalBounds[i] == null) continue;
332
333                 Rectangle2D JavaDoc glyphBounds = tempLogicalBounds[i].getBounds2D();
334                 double y = glyphBounds.getMinY();
335                 double height = glyphBounds.getHeight();
336
337                 if ((i < getNumGlyphs()-1) &&
338                     (tempLogicalBounds[i+1] != null)) {
339                     // make this glyph extend to the start of the next one
340
Rectangle2D JavaDoc ngb = tempLogicalBounds[i+1].getBounds2D();
341                     if (ngb.getY() > y) { // going top to bottom
342
double nh = ngb.getY() - y;
343                         if ((nh < height*1.15) && (nh > height*.85)) {
344                             double delta = (nh-height)*.5;
345                             height += delta;
346                             ngb.setRect(ngb.getX(), ngb.getY()-delta,
347                                         ngb.getWidth(), ngb.getHeight()+delta);
348                         }
349                     }
350                 }
351                 tempLogicalBounds[i] = new Rectangle2D.Double JavaDoc
352                     (fullBounds.getMinX(), y,
353                      fullBounds.getWidth(), height);
354             }
355         }
356
357         for (int i = 0; i < getNumGlyphs(); i++) {
358             glyphLogicalBounds[i] = tempLogicalBounds[i];
359         }
360     }
361
362     /**
363      * Returns the metrics of the glyph at the specified index into this
364      * GlyphVector.
365      */

366     public GVTGlyphMetrics getGlyphMetrics(int idx) {
367
368         if (idx < 0 || (idx > glyphs.length-1))
369             throw new IndexOutOfBoundsException JavaDoc
370                 ("idx: " + idx + ", is out of bounds. Should be between 0 and "
371                  + (glyphs.length-1) + ".");
372
373         // check to see if we should kern this glyph
374
// I return the kerning information in the glyph metrics
375
// as a first pass at implementation (I don't want to
376
// fiddle with layout too much right now).
377
if (idx < glyphs.length - 1) {
378             // check for kerning
379
if (font != null) {
380                 float hkern = font.getHKern(glyphs[idx].getGlyphCode(),
381                                             glyphs[idx+1].getGlyphCode());
382                 float vkern = font.getVKern(glyphs[idx].getGlyphCode(),
383                                             glyphs[idx+1].getGlyphCode());
384                 return glyphs[idx].getGlyphMetrics(hkern, vkern);
385             }
386         }
387
388         // get a normal metrics
389
return glyphs[idx].getGlyphMetrics();
390     }
391
392     /**
393      * Returns a Shape whose interior corresponds to the visual representation
394      * of the specified glyph within this GlyphVector.
395      */

396     public Shape JavaDoc getGlyphOutline(int glyphIndex) {
397         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
398             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
399             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
400         }
401         return glyphs[glyphIndex].getOutline();
402     }
403
404     /**
405      * Returns the position of the specified glyph within this GlyphVector.
406      */

407     public Point2D JavaDoc getGlyphPosition(int glyphIndex) {
408         if (glyphIndex == glyphs.length)
409             return endPos;
410
411         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
412             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
413             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
414         }
415         return glyphs[glyphIndex].getPosition();
416     }
417
418
419     /**
420      * Returns an array of glyph positions for the specified glyphs
421      */

422     public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
423                                      float[] positionReturn) {
424          if (numEntries < 0) {
425             throw new IllegalArgumentException JavaDoc("numEntries argument value, "
426                       + numEntries + ", is illegal. It must be > 0.");
427         }
428         if (beginGlyphIndex < 0) {
429             throw new IndexOutOfBoundsException JavaDoc("beginGlyphIndex " + beginGlyphIndex
430                       + " is out of bounds, should be between 0 and "
431                       + (glyphs.length-1));
432         }
433         if ((beginGlyphIndex+numEntries) > glyphs.length+1) {
434              throw new IndexOutOfBoundsException JavaDoc("beginGlyphIndex + numEntries ("
435                        + beginGlyphIndex + "+" + numEntries
436                        + ") exceeds the number of glpyhs in this GlyphVector");
437         }
438         if (positionReturn == null) {
439             positionReturn = new float[numEntries*2];
440         }
441         if ((beginGlyphIndex+numEntries) == glyphs.length+1) {
442             numEntries--;
443             positionReturn[numEntries*2] = (float)endPos.getX();
444             positionReturn[numEntries*2+1] = (float)endPos.getY();
445         }
446         for (int i = beginGlyphIndex; i < (beginGlyphIndex+numEntries); i++) {
447             Point2D JavaDoc glyphPos;
448             glyphPos = glyphs[i].getPosition();
449             positionReturn[(i-beginGlyphIndex)*2] = (float)glyphPos.getX();
450             positionReturn[(i-beginGlyphIndex)*2 + 1] = (float)glyphPos.getY();
451         }
452         return positionReturn;
453     }
454
455     /**
456      * Gets the transform of the specified glyph within this GlyphVector.
457      */

458     public AffineTransform JavaDoc getGlyphTransform(int glyphIndex) {
459         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
460             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
461             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
462         }
463         return glyphs[glyphIndex].getTransform();
464     }
465
466     /**
467      * Returns the visual bounds of the specified glyph within the GlyphVector.
468      */

469     public Shape JavaDoc getGlyphVisualBounds(int glyphIndex) {
470         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
471             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
472             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
473         }
474         return glyphs[glyphIndex].getOutline();
475     }
476
477     /**
478      * Returns a tight bounds on the GylphVector including stroking.
479      */

480     public Rectangle2D JavaDoc getBounds2D(AttributedCharacterIterator JavaDoc aci) {
481         // System.out.println("GlyphVector.getBounds2D Called: " + this);
482
aci.first();
483         TextPaintInfo tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO);
484         if ((bounds2D != null) &&
485             TextPaintInfo.equivilent(tpi, cacheTPI))
486             return bounds2D;
487
488         Rectangle2D JavaDoc b=null;
489         if (tpi.visible) {
490             for (int i = 0; i < getNumGlyphs(); i++) {
491                 if (!glyphVisible[i]) continue;
492
493                 Rectangle2D JavaDoc glyphBounds = glyphs[i].getBounds2D();
494                 // System.out.println("GB["+i+"]: " + glyphBounds);
495
if (glyphBounds == null) continue;
496                 if (b == null) b=glyphBounds;
497                 else b = glyphBounds.createUnion(b);
498             }
499         }
500
501         bounds2D = b;
502         if ( bounds2D == null ){
503             bounds2D = new Rectangle2D.Float JavaDoc();
504         }
505         cacheTPI = new TextPaintInfo(tpi);
506         return bounds2D;
507     }
508
509     /**
510      * Returns the logical bounds of this GlyphVector.
511      * This is a bound useful for hit detection and highlighting.
512      */

513     public Rectangle2D JavaDoc getLogicalBounds() {
514         if (logicalBounds == null) {
515             GeneralPath JavaDoc logicalBoundsPath = new GeneralPath JavaDoc();
516             for (int i = 0; i < getNumGlyphs(); i++) {
517                 Shape JavaDoc glyphLogicalBounds = getGlyphLogicalBounds(i);
518                 if (glyphLogicalBounds != null) {
519                     logicalBoundsPath.append(glyphLogicalBounds, false);
520                 }
521             }
522             logicalBounds = logicalBoundsPath.getBounds2D();
523         }
524         return logicalBounds;
525     }
526
527     /**
528      * Returns the number of glyphs in this GlyphVector.
529      */

530     public int getNumGlyphs() {
531         if (glyphs != null) {
532             return glyphs.length;
533         }
534         return 0;
535     }
536
537     /**
538      * Returns a Shape whose interior corresponds to the visual representation
539      * of this GlyphVector.
540      */

541     public Shape JavaDoc getOutline() {
542         if (outline == null) {
543             outline = new GeneralPath JavaDoc();
544             for (int i = 0; i < glyphs.length; i++) {
545                 if (glyphVisible[i]) {
546                     Shape JavaDoc glyphOutline = glyphs[i].getOutline();
547                     if (glyphOutline != null) {
548                         outline.append(glyphOutline, false);
549                     }
550                 }
551             }
552         }
553         return outline;
554     }
555
556     /**
557      * Returns a Shape whose interior corresponds to the visual representation
558      * of this GlyphVector, offset to x, y.
559      */

560     public Shape JavaDoc getOutline(float x, float y) {
561         Shape JavaDoc outline = getOutline();
562         AffineTransform JavaDoc tr = AffineTransform.getTranslateInstance(x,y);
563         Shape JavaDoc translatedOutline = tr.createTransformedShape(outline);
564         return translatedOutline;
565     }
566
567     /**
568      * Returns the geometric bounds of this GlyphVector. The geometric
569      * bounds is the tightest rectangle enclosing the geometry of the
570      * glyph vector (not including stroke).
571      */

572     public Rectangle2D JavaDoc getGeometricBounds() {
573         return getOutline().getBounds2D();
574     }
575
576     /**
577      * Assigns default positions to each glyph in this GlyphVector. The default
578      * layout is horizontal.
579      */

580     public void performDefaultLayout() {
581         logicalBounds = null;
582         outline = null;
583         bounds2D = null;
584
585         float currentX = 0;
586         float currentY = 0;
587         for (int i = 0; i < glyphs.length; i++) {
588             Glyph g = glyphs[i];
589             g.setTransform(null);
590             glyphLogicalBounds[i] = null;
591
592             String JavaDoc uni = g.getUnicode();
593             if ((uni != null) && (uni.length() != 0) &&
594                 ArabicTextHandler.arabicCharTransparent(uni.charAt(0))) {
595                 int j;
596                 for (j=i+1; j<glyphs.length; j++) {
597                     uni = glyphs[j].getUnicode();
598                     if ((uni == null) || (uni.length() == 0)) break;
599                     char ch = uni.charAt(0);
600                     if (!ArabicTextHandler.arabicCharTransparent(ch))
601                         break;
602                 }
603                 if (j != glyphs.length) {
604                     Glyph bg = glyphs[j];
605                     float rEdge = (float)(currentX + bg.getHorizAdvX());
606                     for (int k=i; k<j; k++) {
607                         g = glyphs[k];
608                         g.setTransform(null);
609                         glyphLogicalBounds[i] = null;
610                         g.setPosition(new Point2D.Float JavaDoc(rEdge-g.getHorizAdvX(),
611                                                         currentY));
612                     }
613                     i = j;
614                     g = bg;
615                 }
616             }
617
618             g.setPosition(new Point2D.Float JavaDoc(currentX, currentY));
619             currentX += g.getHorizAdvX();
620         }
621         endPos = new Point2D.Float JavaDoc(currentX, currentY);
622     }
623
624     /**
625      * Sets the position of the specified glyph within this GlyphVector.
626      */

627     public void setGlyphPosition(int glyphIndex, Point2D JavaDoc newPos)
628                                  throws IndexOutOfBoundsException JavaDoc {
629         if (glyphIndex == glyphs.length) {
630             endPos = (Point2D JavaDoc)newPos.clone();
631             return;
632         }
633
634         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
635             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
636             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
637         }
638         glyphs[glyphIndex].setPosition(newPos);
639         glyphLogicalBounds[glyphIndex] = null;
640         outline = null;
641         bounds2D = null;
642         logicalBounds = null;
643     }
644
645     /**
646      * Sets the transform of the specified glyph within this GlyphVector.
647      */

648     public void setGlyphTransform(int glyphIndex, AffineTransform JavaDoc newTX) {
649         if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
650             throw new IndexOutOfBoundsException JavaDoc("glyphIndex: " + glyphIndex
651             + ", is out of bounds. Should be between 0 and " + (glyphs.length-1) + ".");
652         }
653         glyphs[glyphIndex].setTransform(newTX);
654         glyphLogicalBounds[glyphIndex] = null;
655         outline = null;
656         bounds2D = null;
657         logicalBounds = null;
658     }
659
660     /**
661      * Tells the glyph vector whether or not to draw the specified glyph.
662      */

663     public void setGlyphVisible(int glyphIndex, boolean visible) {
664         if (visible == glyphVisible[glyphIndex])
665             return;
666
667         glyphVisible[glyphIndex] = visible;
668         outline = null;
669         bounds2D = null;
670         logicalBounds = null;
671         glyphLogicalBounds[glyphIndex] = null;
672     }
673
674     /**
675      * Returns true if specified glyph will be rendered.
676      */

677     public boolean isGlyphVisible(int glyphIndex) {
678         return glyphVisible[glyphIndex];
679     }
680
681     /**
682      * Returns the number of chars represented by the glyphs within the
683      * specified range.
684      * @param startGlyphIndex The index of the first glyph in the range.
685      * @param endGlyphIndex The index of the last glyph in the range.
686      * @return The number of chars.
687      */

688     public int getCharacterCount(int startGlyphIndex, int endGlyphIndex) {
689         int numChars = 0;
690         if (startGlyphIndex < 0) {
691             startGlyphIndex = 0;
692         }
693         if (endGlyphIndex > glyphs.length-1) {
694             endGlyphIndex = glyphs.length-1;
695         }
696         for (int i = startGlyphIndex; i <= endGlyphIndex; i++) {
697             Glyph glyph = glyphs[i];
698             if (glyph.getGlyphCode() == -1) {
699                 // Missing glyph mapps to just one char...
700
numChars++;
701             } else {
702                 String JavaDoc glyphUnicode = glyph.getUnicode();
703                 numChars += glyphUnicode.length();
704             }
705         }
706         return numChars;
707     }
708
709     /**
710      * Draws this glyph vector.
711      */

712     public void draw(Graphics2D JavaDoc graphics2D,
713                      AttributedCharacterIterator JavaDoc aci) {
714         aci.first();
715         TextPaintInfo tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO);
716         if (!tpi.visible) return;
717
718         for (int i = 0; i < glyphs.length; i++) {
719             if (glyphVisible[i]) {
720                 glyphs[i].draw(graphics2D);
721             }
722         }
723     }
724 }
725
726
Popular Tags