1    // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
2    package org.xwt;
3    import org.xwt.translators.*;
4    import org.xwt.util.*;
5    import org.xwt.js.*;
6    import java.util.*;
7    
8    public class Glyph {
9        public char c;
10       public int max_ascent;     // same value for every glyph in font; the max ascent of all chars
11       public int max_descent;    // same value for every glyph in font; the max descent of all chars
12       public int baseline;       // within the picture, this is the y-coordinate of the baseline
13       public int advance;        // amount to increment the x-coordinate
14       public int pointsize;
15       public Picture p;
16       public Res res;
17       public boolean rendered = false;
18   
19       // k1=font.res k2=(c << 16 | pointsize)
20       private static Cache glyphCache = new Cache();
21   
22       private static Queue glyphsToBeRendered = new Queue(255);
23       private static Freetype freetype = new Freetype();
24   
25       private static Scheduler.Task glyphRenderingTask = new Scheduler.Task() {
26               public Object call(Object arg) {
27                   Glyph g = (Glyph)glyphsToBeRendered.remove(false);
28                   if (g == null) return null;
29                   if (g.p != null) return null;
30                   Log.log(Glyph.class, "rendering glyph " + g.c);
31                   freetype.renderGlyph(g.res, g);
32                   g.rendered = true;
33                   Scheduler.add(this);
34                   return null;
35               }
36           };
37   
38       /**
39   
40        *  If the glyphs of <code>text</code> are not yet loaded, spawn a
41        *  Task to load them and invoke callback.
42        *
43   
44        *  returns the width (in the high-order int) and height (in the
45        *  low-order int) of the string's rasterization, or -1 if some
46        *  glyphs are not loaded.
47   
48        */
49       public static long rasterizeGlyphs(final Res res, final int pointsize, final String text, PixelBuffer pb, int textcolor,
50                                     int x, int y, int cx1, int cy1, int cx2, int cy2, final Callback callback) {
51           boolean ret = true;
52           int width = 0;
53           int height = 0;
54           for(int i=0; i<text.length(); i++) {
55               final char c = text.charAt(i);
56               Glyph g = (Glyph)glyphCache.get(res, new Integer((((int)c) << 16) | pointsize));
57               if (g == null) {
58                   g = new Glyph();
59                   g.c = c;
60                   g.pointsize = pointsize;
61                   g.res = res; 
62                   glyphCache.put(res, new Integer((((int)c) << 16) | pointsize), g);
63                   glyphsToBeRendered.prepend(g);
64               }
65               if (g.rendered && ret) {
66                   if (pb != null && g.p != null)
67                       pb.drawPictureAlphaOnly(g.p, x, y + g.max_ascent - g.baseline, cx1, cy1, cx2, cy2, textcolor);
68                   x += g.advance;
69                   width += g.advance;
70                   height = java.lang.Math.max(height, g.max_ascent + g.max_descent);
71               } else {
72                   glyphsToBeRendered.prepend(g);
73                   Scheduler.add(glyphRenderingTask);
74                   ret = false;
75               }
76           }
77           if (!ret) Scheduler.add(new Scheduler.Task() { public Object call(Object arg) {
78               for(int i=0; i<text.length(); i++) {
79                   Glyph g = (Glyph)glyphCache.get(res, new Integer((((int)text.charAt(i)) << 16) | pointsize));
80                   if (g == null || !g.rendered) {
81                       Scheduler.add(this);
82                       return null;
83                   }
84               }
85               callback.call(null);
86               return null;
87           }});
88   
89           if (ret) return ((long)width << 16) | (long)height;
90           for(int i=32; i<128; i++) {
91               Glyph g = (Glyph)glyphCache.get(res, new Integer((i << 16) | pointsize));
92               if (g == null) {
93                   g = new Glyph();
94                   g.c = (char)i;
95                   g.pointsize = pointsize;
96                   g.res = res;
97                   glyphCache.put(res, new Integer((i << 16) | pointsize), g);
98                   glyphsToBeRendered.append(g);
99               }
100          }
101          return -1;
102      }
103  }
104