KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > bridge > SVGGVTFont


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.bridge;
19
20 import java.awt.Font JavaDoc;
21 import java.awt.Paint JavaDoc;
22 import java.awt.Stroke JavaDoc;
23 import java.awt.font.FontRenderContext JavaDoc;
24 import java.awt.font.TextAttribute JavaDoc;
25 import java.text.AttributedCharacterIterator JavaDoc;
26 import java.text.CharacterIterator JavaDoc;
27 import java.text.StringCharacterIterator JavaDoc;
28 import java.util.StringTokenizer JavaDoc;
29 import java.util.Vector JavaDoc;
30
31 import org.apache.batik.css.engine.SVGCSSEngine;
32 import org.apache.batik.css.engine.value.Value;
33 import org.apache.batik.dom.util.XMLSupport;
34 import org.apache.batik.gvt.font.GVTFont;
35 import org.apache.batik.gvt.font.GVTFontFace;
36 import org.apache.batik.gvt.font.GVTGlyphVector;
37 import org.apache.batik.gvt.font.GVTLineMetrics;
38 import org.apache.batik.gvt.font.Glyph;
39 import org.apache.batik.gvt.font.Kern;
40 import org.apache.batik.gvt.font.KerningTable;
41 import org.apache.batik.gvt.font.SVGGVTGlyphVector;
42 import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
43 import org.apache.batik.gvt.text.TextPaintInfo;
44 import org.apache.batik.util.SVGConstants;
45 import org.w3c.dom.Element JavaDoc;
46
47 /**
48  * Represents an SVG font.
49  *
50  * @author <a HREF="mailto:bella.robinson@cmis.csiro.au">Bella Robinson</a>
51  * @version $Id: SVGGVTFont.java,v 1.19 2005/03/27 08:58:30 cam Exp $
52  */

53 public final class SVGGVTFont implements GVTFont, SVGConstants {
54
55     public static final AttributedCharacterIterator.Attribute JavaDoc PAINT_INFO
56         = GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO;
57
58     private float fontSize;
59     private GVTFontFace fontFace;
60     private String JavaDoc[] glyphUnicodes;
61     private String JavaDoc[] glyphNames;
62     private String JavaDoc[] glyphLangs;
63     private String JavaDoc[] glyphOrientations;
64     private String JavaDoc[] glyphForms;
65     private Element JavaDoc[] glyphElements;
66     private Element JavaDoc[] hkernElements;
67     private Element JavaDoc[] vkernElements;
68     private BridgeContext ctx;
69     private Element JavaDoc textElement;
70     private Element JavaDoc missingGlyphElement;
71     private KerningTable hKerningTable;
72     private KerningTable vKerningTable;
73     private String JavaDoc language;
74     private String JavaDoc orientation;
75     private float scale;
76     private GVTLineMetrics lineMetrics=null;
77
78     /**
79      * Constructs a new SVGGVTFont of the specified size.
80      *
81      * @param fontSize The size of the font to create.
82      * @param fontFace The font face that describes the font.
83      * @param glyphUnicodes An array containing the unicode values for
84      * all the glyphs this font can display.
85      * @param glyphNames An array containing the names of all the
86      * glyphs this font can display.
87      * @param ctx The bridge context.
88      * @param glyphElements An array containing the children glyph
89      * elements of the SVG font.
90      * @param missingGlyphElement The missing glyph element for this
91      * font.
92      * @param hkernElements An array containing all hkern elements for
93      * this font.
94      * @param vkernElements An array containing all vkern elements for
95      * this font.
96      * @param textElement The text element that contains the text to
97      * be rendered using this font.
98      */

99     public SVGGVTFont(float fontSize,
100                       GVTFontFace fontFace,
101                       String JavaDoc[] glyphUnicodes,
102                       String JavaDoc[] glyphNames,
103                       String JavaDoc[] glyphLangs,
104                       String JavaDoc[] glyphOrientations,
105                       String JavaDoc[] glyphForms,
106                       BridgeContext ctx,
107                       Element JavaDoc[] glyphElements,
108                       Element JavaDoc missingGlyphElement,
109                       Element JavaDoc[] hkernElements,
110                       Element JavaDoc[] vkernElements,
111                       Element JavaDoc textElement) {
112         this.fontFace = fontFace;
113         this.fontSize = fontSize;
114         this.glyphUnicodes = glyphUnicodes;
115         this.glyphNames = glyphNames;
116         this.glyphLangs = glyphLangs;
117         this.glyphOrientations = glyphOrientations;
118         this.glyphForms = glyphForms;
119         this.ctx = ctx;
120         this.glyphElements = glyphElements;
121         this.missingGlyphElement = missingGlyphElement;
122         this.hkernElements = hkernElements;
123         this.vkernElements = vkernElements;
124         this.scale = fontSize/fontFace.getUnitsPerEm();
125         this.textElement = textElement;
126
127         this.language = XMLSupport.getXMLLang(textElement);
128
129         Value v = CSSUtilities.getComputedStyle
130             (textElement, SVGCSSEngine.WRITING_MODE_INDEX);
131         if (v.getStringValue().startsWith(CSS_TB_VALUE)) {
132             // top to bottom, so set orientation to "v"
133
this.orientation = SVG_V_VALUE;
134         } else {
135             this.orientation = SVG_H_VALUE;
136         }
137
138         createKerningTables();
139     }
140
141
142     /**
143      * Creates the kerning tables for this font. Two tables are created,
144      * horizontal and vertical. If there are not children vkern or hkern
145      * elements these tables will be empty.
146      */

147     private void createKerningTables() {
148
149         Kern[] hEntries = new Kern[hkernElements.length];
150         for (int i = 0; i < hkernElements.length; i++) {
151             Element JavaDoc hkernElement = hkernElements[i];
152             SVGHKernElementBridge hkernBridge =
153                 (SVGHKernElementBridge)ctx.getBridge(hkernElement);
154             Kern hkern = hkernBridge.createKern(ctx, hkernElement, this);
155             hEntries[i] = hkern;
156         }
157         hKerningTable = new KerningTable(hEntries);
158
159         Kern[] vEntries = new Kern[vkernElements.length];
160         for (int i = 0; i < vkernElements.length; i++) {
161             Element JavaDoc vkernElement = vkernElements[i];
162             SVGVKernElementBridge vkernBridge =
163                 (SVGVKernElementBridge)ctx.getBridge(vkernElement);
164             Kern vkern = vkernBridge.createKern(ctx, vkernElement, this);
165             vEntries[i] = vkern;
166         }
167         vKerningTable = new KerningTable(vEntries);
168
169     }
170
171     /**
172      * Returns the horizontal kerning value for the specified glyph pair.
173      * This will be zero if there is no explicit horizontal kerning value
174      * for this particular glyph pair.
175      *
176      * @param glyphCode1 The id of the first glyph.
177      * @param glyphCode2 The id of the second glyph.
178      *
179      * @return The horizontal kerning value.
180      */

181     public float getHKern(int glyphCode1, int glyphCode2) {
182         if (glyphCode1 < 0 || glyphCode1 >= glyphUnicodes.length
183             || glyphCode2 < 0 || glyphCode2 >= glyphUnicodes.length) {
184             return 0f;
185         }
186         float ret;
187         ret = hKerningTable.getKerningValue(glyphCode1, glyphCode2,
188                                             glyphUnicodes[glyphCode1],
189                                             glyphUnicodes[glyphCode2]);
190         return ret*scale;
191     }
192
193     /**
194      * Returns the vertical kerning value for the specified glyph pair.
195      * This will be zero if there is no explicit vertical kerning value for
196      * for this particular glyph pair.
197      *
198      * @param glyphCode1 The id of the first glyph.
199      * @param glyphCode2 The id of the second glyph.
200      *
201      * @return The vertical kerning value.
202      */

203     public float getVKern(int glyphCode1, int glyphCode2) {
204         if (glyphCode1 < 0 || glyphCode1 >= glyphUnicodes.length
205             || glyphCode2 < 0 || glyphCode2 >= glyphUnicodes.length) {
206             return 0f;
207         }
208         float ret;
209         ret = vKerningTable.getKerningValue(glyphCode1, glyphCode2,
210                                             glyphUnicodes[glyphCode1],
211                                             glyphUnicodes[glyphCode2]);
212         return ret*scale;
213     }
214
215     /**
216      * Returns an array of glyph codes (unique ids) of the glyphs with the
217      * specified name (there may be more than one).
218      *
219      * @param name The name of the glyph.
220      *
221      * @return An array of matching glyph codes. This may be empty.
222      */

223     public int[] getGlyphCodesForName(String JavaDoc name) {
224         Vector JavaDoc glyphCodes = new Vector JavaDoc();
225         for (int i = 0; i < glyphNames.length; i++) {
226             if (glyphNames[i] != null && glyphNames[i].equals(name)) {
227                 glyphCodes.add(new Integer JavaDoc(i));
228             }
229         }
230         int[] glyphCodeArray = new int[glyphCodes.size()];
231         for (int i = 0; i < glyphCodes.size(); i++) {
232             glyphCodeArray[i] = ((Integer JavaDoc)glyphCodes.elementAt(i)).intValue();
233         }
234         return glyphCodeArray;
235     }
236
237     /**
238      * Returns an array of glyph codes (unique ids) of the glyphs with the
239      * specified unicode value (there may be more than one).
240      *
241      * @param unicode The unicode value of the glyph.
242      *
243      * @return An array of matching glyph codes. This may be empty.
244      */

245     public int[] getGlyphCodesForUnicode(String JavaDoc unicode) {
246         Vector JavaDoc glyphCodes = new Vector JavaDoc();
247         for (int i = 0; i < glyphUnicodes.length; i++) {
248             if (glyphUnicodes[i] != null && glyphUnicodes[i].equals(unicode)) {
249                 glyphCodes.add(new Integer JavaDoc(i));
250             }
251         }
252         int[] glyphCodeArray = new int[glyphCodes.size()];
253         for (int i = 0; i < glyphCodes.size(); i++) {
254             glyphCodeArray[i] = ((Integer JavaDoc)glyphCodes.elementAt(i)).intValue();
255         }
256         return glyphCodeArray;
257     }
258
259     /**
260      * Returns true if the glyph language matches the language of the
261      * text node to be rendered by this font. This will be the case
262      * if one of the languages in glyphLang matches exactly with the
263      * xml:lang attibute of the text node, or if the xml:lang
264      * attribute exactly equals a prefix of one glyph languages.
265      *
266      * @param glyphLang A comma separated list of languages that are associated
267      * with a glyph.
268      *
269      * @return Whether or not the glyph language matches the language of the
270      * text node.
271      */

272     private boolean languageMatches(String JavaDoc glyphLang) {
273         if (glyphLang == null || glyphLang.length() == 0) {
274             return true; // will match all languages
275
}
276         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(glyphLang, ",");
277         while (st.hasMoreTokens()) {
278             String JavaDoc s = st.nextToken();
279             if (s.equals(language)
280                || (s.startsWith(language) && s.length() > language.length()
281                    && s.charAt(language.length()) == '-')) {
282                 return true;
283             }
284         }
285         return false;
286     }
287
288     /**
289      * Returns true if the glyph orientation matches the orientation of the
290      * text node to be rendered by this font.
291      *
292      * @param glyphOrientation The glyph orientation attribute value. Will be
293      * "h", "v" or empty.
294      *
295      * @return Whether or not the glyph orientation matches the text to be
296      * rendered by this font object.
297      */

298     private boolean orientationMatches(String JavaDoc glyphOrientation) {
299         if (glyphOrientation == null || glyphOrientation.length() == 0) {
300             return true;
301         }
302         return glyphOrientation.equals(orientation);
303     }
304
305
306     /**
307      * Returns true if the glyph form matches that of the current character in
308      * the aci.
309      *
310      * @param glyphUnicode The unicode value of the glyph.
311      * @param glyphForm The arabic-form glyph attribute.
312      * @param aci The aci containing the character to check.
313      * @param currentIndex The index of the character to check.
314      */

315     private boolean formMatches(String JavaDoc glyphUnicode,
316                                 String JavaDoc glyphForm,
317                                 AttributedCharacterIterator JavaDoc aci,
318                                 int currentIndex) {
319         if (aci == null || glyphForm == null || glyphForm.length() == 0) {
320             // there aren't any attributes attached to the text
321
// or the glyph doesn't have an arabic form
322
return true;
323         }
324
325         char c = aci.setIndex(currentIndex);
326         Integer JavaDoc form = (Integer JavaDoc)aci.getAttribute
327             (GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM);
328
329         if (form == null || form.equals
330             (GVTAttributedCharacterIterator.TextAttribute.ARABIC_NONE)) {
331             // the glyph has an arabic form and the current character
332
// form is "none" so don't match
333
return false;
334         }
335
336         // see if c is the start of an arabic ligature
337
if (glyphUnicode.length() > 1) {
338
339             boolean matched = true;
340             for (int j = 1; j < glyphUnicode.length(); j++) {
341                 c = aci.next();
342                 if (glyphUnicode.charAt(j) != c) {
343                     matched = false;
344                     break;
345                 }
346             }
347
348             // reset the aci
349
aci.setIndex(currentIndex);
350
351             if (matched) {
352
353                 // ligature matches, now check that the arabic forms are ok
354
aci.setIndex(currentIndex + glyphUnicode.length() - 1);
355                 Integer JavaDoc lastForm = (Integer JavaDoc)aci.getAttribute(
356                     GVTAttributedCharacterIterator.TextAttribute.ARABIC_FORM);
357
358                 // reset the aci again
359
aci.setIndex(currentIndex);
360
361                 if (form != null && lastForm != null) {
362                     if (form.equals(GVTAttributedCharacterIterator.
363                                     TextAttribute.ARABIC_TERMINAL) &&
364                         lastForm.equals(GVTAttributedCharacterIterator.
365                                         TextAttribute.ARABIC_INITIAL)) {
366                         // return true if the glyph form is isolated
367
return glyphForm.equals
368                             (SVGConstants.SVG_ISOLATED_VALUE);
369
370                     } else if (form.equals(GVTAttributedCharacterIterator.
371                                            TextAttribute.ARABIC_TERMINAL)) {
372                         // return true if the glyph form is terminal
373
return glyphForm.equals
374                             (SVGConstants.SVG_TERMINAL_VALUE);
375
376                     } else if (form.equals(GVTAttributedCharacterIterator.
377                                            TextAttribute.ARABIC_MEDIAL) &&
378                                lastForm.equals(GVTAttributedCharacterIterator.
379                                                TextAttribute.ARABIC_MEDIAL)) {
380                         // return true if the glyph form is medial
381
return glyphForm.equals(SVGConstants.SVG_MEDIAL_VALUE);
382                     }
383                     // should test for other combos as well here
384
}
385             }
386         }
387
388         if (form.equals(GVTAttributedCharacterIterator.
389                         TextAttribute.ARABIC_ISOLATED)) {
390             return glyphForm.equals(SVGConstants.SVG_ISOLATED_VALUE);
391         }
392         if (form.equals(GVTAttributedCharacterIterator.
393                         TextAttribute.ARABIC_TERMINAL)) {
394             return glyphForm.equals(SVGConstants.SVG_TERMINAL_VALUE);
395         }
396         if (form.equals(GVTAttributedCharacterIterator.
397                         TextAttribute.ARABIC_INITIAL)) {
398             return glyphForm.equals(SVGConstants.SVG_INITIAL_VALUE);
399         }
400         if (form.equals(GVTAttributedCharacterIterator.
401                         TextAttribute.ARABIC_MEDIAL)) {
402             return glyphForm.equals(SVGConstants.SVG_MEDIAL_VALUE);
403         }
404         return false;
405     }
406
407     /**
408      * Indicates whether or not the specified glyph can be displayed by this
409      * font.
410      *
411      * @param name The name of the glyph to check.
412      *
413      * @return true if the glyph can be displayed.
414      */

415     public boolean canDisplayGivenName(String JavaDoc name) {
416         for (int i = 0; i < glyphNames.length; i++) {
417             if (glyphNames[i] != null && glyphNames[i].equals(name)
418                 && languageMatches(glyphLangs[i])
419                 && orientationMatches(glyphOrientations[i])) {
420                 return true;
421             }
422         }
423         return false;
424     }
425
426
427     /**
428      * Indicates whether or not the specified character can be
429      * displayed by this font.
430      *
431      * @param c The character to check.
432      *
433      * @return true if the character can be displayed.
434      */

435     public boolean canDisplay(char c) {
436         for (int i = 0; i < glyphUnicodes.length; i++) {
437             if (glyphUnicodes[i].indexOf(c) != -1
438                 && languageMatches(glyphLangs[i])
439                 && orientationMatches(glyphOrientations[i])) {
440                 return true;
441             }
442         }
443         return false;
444     }
445
446     /**
447      * Checks whether this Font can display the characters in the
448      * specified character array starting at start and ending at limit.
449      *
450      * @param text An array containing the characters to check.
451      * @param start The index of the first character to check.
452      * @param limit The index of the last character to check.
453      *
454      * @return The index of the first character it can't display or -1 if
455      * it can display the whole string.
456      */

457     public int canDisplayUpTo(char[] text, int start, int limit) {
458         StringCharacterIterator JavaDoc sci =
459             new StringCharacterIterator JavaDoc(new String JavaDoc(text));
460         return canDisplayUpTo(sci, start, limit);
461     }
462
463     /**
464      * Checks whether this Font can display the characters in the
465      * specified character iterator starting at start and ending at limit.
466      *
467      * @param iter The iterator containing the characters to check.
468      * @param start The index of the first character to check.
469      * @param limit The index of the last character to check.
470      *
471      * @return The index of the first character it can't display or -1 if
472      * it can display the whole string.
473      */

474     public int canDisplayUpTo(CharacterIterator JavaDoc iter, int start, int limit) {
475
476         AttributedCharacterIterator JavaDoc aci = null;
477         if (iter instanceof AttributedCharacterIterator JavaDoc) {
478             aci = (AttributedCharacterIterator JavaDoc)iter;
479         }
480
481         char c = iter.setIndex(start);
482         int currentIndex = start;
483
484         while (c != CharacterIterator.DONE && currentIndex < limit) {
485
486             boolean foundMatchingGlyph = false;
487
488             for (int i = 0; i < glyphUnicodes.length; i++) {
489                 if (glyphUnicodes[i].indexOf(c) == 0
490                     && languageMatches(glyphLangs[i])
491                     && orientationMatches(glyphOrientations[i])
492                     && formMatches(glyphUnicodes[i], glyphForms[i],
493                                    aci, currentIndex)) {
494                     // found a possible match
495

496                     if (glyphUnicodes[i].length() == 1) { // not a ligature
497
foundMatchingGlyph = true;
498                         break;
499
500                     } else {
501                         // glyphCodes[i] is a ligature so try and
502
// match the rest of the glyphCode chars
503
boolean matched = true;
504                         for (int j = 1; j < glyphUnicodes[i].length(); j++) {
505                             c = iter.next();
506                             if (glyphUnicodes[i].charAt(j) != c) {
507                                 matched = false;
508                                 break;
509                             }
510                         }
511                         if (matched) { // found a matching ligature!
512
foundMatchingGlyph = true;
513                             break;
514
515                         } else {
516                             // did not match ligature, keep looking
517
// for another glyph
518
c = iter.setIndex(currentIndex);
519                         }
520                     }
521                 }
522             }
523             if (!foundMatchingGlyph) {
524                 return currentIndex;
525             }
526             c = iter.next();
527             currentIndex = iter.getIndex();
528         }
529         return -1;
530     }
531
532     /**
533      * Checks whether or not this font can display the characters in the
534      * specified String.
535      *
536      * @param str The string containing the characters to check.
537      *
538      * @return The index of the first character it can't display or -1 if
539      * it can display the whole string.
540      */

541     public int canDisplayUpTo(String JavaDoc str) {
542         StringCharacterIterator JavaDoc sci = new StringCharacterIterator JavaDoc(str);
543         return canDisplayUpTo(sci, 0, str.length());
544     }
545
546     /**
547      * Returns a new GVTGlyphVector object for the specified array of
548      * characters.
549      *
550      * @param frc The current font render context.
551      * @param chars The array of chars that the glyph vector will represent.
552      *
553      * @return The new glyph vector.
554      */

555     public GVTGlyphVector createGlyphVector(FontRenderContext JavaDoc frc,
556                                             char[] chars) {
557          StringCharacterIterator JavaDoc sci =
558              new StringCharacterIterator JavaDoc(new String JavaDoc(chars));
559          return createGlyphVector(frc, sci);
560     }
561
562     /**
563      * Returns a new GVTGlyphVector object for the characters in the
564      * specified character iterator.
565      *
566      * @param frc The current font render context.
567      * @param ci The character iterator that the glyph vector will represent.
568      *
569      * @return The new glyph vector.
570      */

571     public GVTGlyphVector createGlyphVector(FontRenderContext JavaDoc frc,
572                                             CharacterIterator JavaDoc ci) {
573
574         AttributedCharacterIterator JavaDoc aci = null;
575         if (ci instanceof AttributedCharacterIterator JavaDoc) {
576             aci = (AttributedCharacterIterator JavaDoc)ci;
577         }
578
579         Vector JavaDoc glyphs = new Vector JavaDoc();
580         char c = ci.first();
581         while (c != CharacterIterator.DONE) {
582             boolean foundMatchingGlyph = false;
583             for (int i = 0; i < glyphUnicodes.length; i++) {
584                 if (glyphUnicodes[i].indexOf(c) == 0 &&
585                     languageMatches(glyphLangs[i]) &&
586                     orientationMatches(glyphOrientations[i]) &&
587                     formMatches(glyphUnicodes[i], glyphForms[i], aci,
588                                 ci.getIndex())) { // found a possible match
589

590                     if (glyphUnicodes[i].length() == 1) { // not a ligature
591
Element JavaDoc glyphElement = glyphElements[i];
592                         SVGGlyphElementBridge glyphBridge =
593                             (SVGGlyphElementBridge)ctx.getBridge(glyphElement);
594                         TextPaintInfo tpi = null;
595                         if (aci != null) {
596                             tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO);
597                         }
598                         Glyph glyph = glyphBridge.createGlyph
599                             (ctx, glyphElement, textElement, i,
600                              fontSize, fontFace, tpi);
601                         glyphs.add(glyph);
602                         foundMatchingGlyph = true;
603                         break;
604                     } else {
605                         // glyphCodes[i] is a ligature so try and
606
// match the rest of the glyphCode chars
607
int current = ci.getIndex();
608                         boolean matched = true;
609                         for (int j = 1; j < glyphUnicodes[i].length(); j++) {
610                             c = ci.next();
611                             if (glyphUnicodes[i].charAt(j) != c) {
612                                 matched = false;
613                                 break;
614                             }
615                         }
616                         if (matched) { // found a matching ligature!
617

618                             Element JavaDoc glyphElement = glyphElements[i];
619                             SVGGlyphElementBridge glyphBridge
620                                 = (SVGGlyphElementBridge)ctx.getBridge
621                                 (glyphElement);
622                             TextPaintInfo tpi = null;
623                             if (aci != null) {
624                                 aci.setIndex(ci.getIndex());
625                                 tpi = (TextPaintInfo)aci.getAttribute
626                                     (PAINT_INFO);
627                             }
628                             Glyph glyph = glyphBridge.createGlyph
629                                 (ctx, glyphElement, textElement, i,
630                                  fontSize, fontFace, tpi);
631                             glyphs.add(glyph);
632                             foundMatchingGlyph = true;
633                             break;
634
635                         } else {
636                             // did not match ligature, keep looking
637
// for another glyph
638
c = ci.setIndex(current);
639                         }
640                     }
641                 }
642             }
643             if (!foundMatchingGlyph) {
644                 // add the missing glyph
645
SVGGlyphElementBridge glyphBridge =
646                     (SVGGlyphElementBridge)ctx.getBridge(missingGlyphElement);
647                 TextPaintInfo tpi = null;
648                 if (aci != null) {
649                     aci.setIndex(ci.getIndex());
650                     tpi = (TextPaintInfo)aci.getAttribute(PAINT_INFO);
651                 }
652                 Glyph glyph = glyphBridge.createGlyph
653                     (ctx, missingGlyphElement, textElement, -1,
654                      fontSize, fontFace, tpi);
655                 glyphs.add(glyph);
656             }
657             c = ci.next();
658         }
659
660         // turn the vector of glyphs into an array;
661
int numGlyphs = glyphs.size();
662         Glyph[] glyphArray = new Glyph[numGlyphs];
663         for (int i =0; i < numGlyphs; i++) {
664             glyphArray[i] = (Glyph)glyphs.get(i);
665         }
666         // return a new SVGGVTGlyphVector
667
return new SVGGVTGlyphVector(this, glyphArray, frc);
668     }
669
670     /**
671      * Returns a new GVTGlyphVector object for the glyphs in the
672      * the glyph code array.
673      *
674      * @param frc The current font render context.
675      * @param glyphCodes An array containin the ids of the glyphs that
676      * the glyph vector will represent.
677      *
678      * @return The new glyph vector.
679      */

680     public GVTGlyphVector createGlyphVector(FontRenderContext JavaDoc frc,
681                                             int[] glyphCodes,
682                                             CharacterIterator JavaDoc ci) {
683         // costruct a string from the glyphCodes
684
String JavaDoc str = "";
685         for (int i = 0; i < glyphCodes.length; i++) {
686             str += glyphUnicodes[glyphCodes[i]];
687         }
688         StringCharacterIterator JavaDoc sci = new StringCharacterIterator JavaDoc(str);
689         return createGlyphVector(frc, sci);
690     }
691
692     /**
693      * Returns a new GVTGlyphVector object for the specified String.
694      *
695      * @param frc The current font render context.
696      * @param str The string that the glyph vector will represent.
697      *
698      * @return The new glyph vector.
699      */

700     public GVTGlyphVector createGlyphVector(FontRenderContext JavaDoc frc,
701                                             String JavaDoc str) {
702         StringCharacterIterator JavaDoc sci = new StringCharacterIterator JavaDoc(str);
703         return createGlyphVector(frc, sci);
704     }
705
706     /**
707      * Creates a new GVTFont object by replicating this font object and
708      * applying a new size to it.
709      *
710      * @param size The size of the new font.
711      *
712      * @return The new font object.
713      */

714     public GVTFont deriveFont(float size) {
715         return new SVGGVTFont(size, fontFace, glyphUnicodes, glyphNames,
716                               glyphLangs, glyphOrientations, glyphForms, ctx,
717                               glyphElements, missingGlyphElement,
718                               hkernElements, vkernElements, textElement);
719     }
720
721     protected GVTLineMetrics getLineMetrics(int beginIndex, int limit) {
722         if (lineMetrics != null)
723             return lineMetrics;
724
725         float fontHeight = fontFace.getUnitsPerEm();
726         float scale = fontSize/fontHeight;
727
728         float ascent = fontFace.getAscent() * scale;
729         float descent = fontFace.getDescent() * scale;
730
731         float[] baselineOffsets = new float[3];
732         baselineOffsets[Font.ROMAN_BASELINE] = 0;
733         baselineOffsets[Font.CENTER_BASELINE] = (ascent+descent)/2-ascent;
734         baselineOffsets[Font.HANGING_BASELINE] = -ascent;
735
736         float stOffset = fontFace.getStrikethroughPosition() * -scale;
737         float stThickness = fontFace.getStrikethroughThickness() * scale;
738         float ulOffset = fontFace.getUnderlinePosition() * scale;
739         float ulThickness = fontFace.getUnderlineThickness() * scale;
740         float olOffset = fontFace.getOverlinePosition() * -scale;
741         float olThickness = fontFace.getOverlineThickness() * scale;
742
743
744         lineMetrics = new GVTLineMetrics
745             (ascent, Font.ROMAN_BASELINE, baselineOffsets, descent,
746              fontHeight, fontHeight, limit-beginIndex,
747              stOffset, stThickness,
748              ulOffset, ulThickness,
749              olOffset, olThickness);
750         return lineMetrics;
751     }
752
753     /**
754      * Returns the line metrics for the specified text.
755      *
756      * @param chars The character array containing the text.
757      * @param beginIndex The index of the first character.
758      * @param limit The limit of characters.
759      * @param frc The current font render context.
760      *
761      * @return The new GVTLineMetrics object.
762      */

763     public GVTLineMetrics getLineMetrics(char[] chars, int beginIndex,
764                                          int limit,
765                                          FontRenderContext JavaDoc frc) {
766         return getLineMetrics(beginIndex, limit);
767     }
768
769     /**
770      * Returns the line metrics for the specified text.
771      *
772      * @param ci The character iterator containing the text.
773      * @param beginIndex The index of the first character.
774      * @param limit The limit of characters.
775      * @param frc The current font render context.
776      *
777      * @return The new GVTLineMetrics object.
778      */

779     public GVTLineMetrics getLineMetrics(CharacterIterator JavaDoc ci, int beginIndex,
780                                          int limit, FontRenderContext JavaDoc frc) {
781         return getLineMetrics(beginIndex, limit);
782     }
783
784     /**
785      * Returns the line metrics for the specified text.
786      *
787      * @param str The string containing the text.
788      * @param frc The current font render context.
789      *
790      * @return The new GVTLineMetrics object.
791      */

792     public GVTLineMetrics getLineMetrics(String JavaDoc str, FontRenderContext JavaDoc frc) {
793         StringCharacterIterator JavaDoc sci = new StringCharacterIterator JavaDoc(str);
794         return getLineMetrics(sci, 0, str.length(), frc);
795     }
796
797     /**
798      * Returns the line metrics for the specified text.
799      *
800      * @param str The string containing the text.
801      * @param beginIndex The index of the first character.
802      * @param limit The limit of characters.
803      * @param frc The current font render context.
804      *
805      * @return The new GVTLineMetrics object.
806      */

807     public GVTLineMetrics getLineMetrics(String JavaDoc str, int beginIndex, int limit,
808                                          FontRenderContext JavaDoc frc) {
809         StringCharacterIterator JavaDoc sci = new StringCharacterIterator JavaDoc(str);
810         return getLineMetrics(sci, beginIndex, limit, frc);
811     }
812
813     /**
814      * Returns the size of this font.
815      *
816      * @return The font size.
817      */

818     public float getSize() {
819         return fontSize;
820     }
821
822     /**
823      * Returns a string representation of this font.
824      * This is for debugging purposes only.
825      *
826      * @return A string representation of this font.
827      */

828     public String JavaDoc toString() {
829         return fontFace.getFamilyName() + " " + fontFace.getFontWeight() + " "
830               + fontFace.getFontStyle();
831     }
832 }
833
Popular Tags