questionable patch: merge of a lot of stuff from the svg branch
[org.ibex.core.git] / src / org / ibex / graphics / Freetype.c
1 // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
2
3 #include <unistd.h>
4 #include <freetype/freetype.h>
5
6 /* NOTE: _user_info is defined in crt0.c. It points to a 4096 byte
7    block of memory that contains 1024 32-bit values that can be set
8    with the setUserInfo() method of MIPSEmu.
9
10    The VM will pause after initialization.  When unpaused, it expects
11    that:
12
13      user_info[0] = ptr to font byte stream in memory
14      user_info[1] = length of font stream
15      user_info[2] = unicode index of first glyph to render
16      user_info[3] = unicode index of last glyph to render
17      user_info[4] = point size to render in
18
19    The VM will then iterate over the requested glyphs, performing the
20    following actions for each glyph:
21    
22      - render the glyph
23      - store the address of the glyph bitmap in user_info[5]
24      - store the width of the glyph bitmap in user_info[6]
25      - store the height of the glyph bitmap in user_info[7]
26      - store the font's ascender into user_info[8]
27      - store the font's height into user_info[9]
28      - store the glyph's ascender into user_info[10]
29      - store the glyph's advance into user_info[11]
30
31    The VM will then pause after each glyph.  The VM should not be
32    unpaused after the last glyph until the next glyph set has been
33    configured in user_info (ie it does not pause twice).
34
35 */
36
37 #if 0
38 extern int user_info[1024];
39 #else
40 /* HACK: This really doesn't belong here... */
41 int user_info[1024];
42
43 extern int mspack_main();
44 int freetype_main();
45
46 int main(int argc, char **argv) {
47     if(argc < 1) return 1;
48     if(strcmp(argv[0],"mspack")==0) return mspack_main();
49     if(strcmp(argv[0],"freetype")==0) return freetype_main();
50     return 1;
51 }
52 #endif
53
54
55 #define FT_Check(expr) do { \
56     if((expr) != 0) { \
57         errprint(#expr " failed\n"); \
58         exit(EXIT_FAILURE); \
59     } \
60 } while(0)
61
62 #define max(a, b) ((a) > (b) ? (a) : (b))
63 #define min(a, b) ((a) < (b) ? (a) : (b))
64
65 static int errprint(const char *s) {
66     int l = strlen(s);
67     int n;
68     while(l) {
69         n = write(STDERR_FILENO,s,l);
70         if(n < 0) return n;
71         l -= n;
72         s += n;
73     }
74     return 0;
75 }
76
77 extern void _pause();
78
79 static FT_Library  library;   /* handle to library     */
80 static FT_Face     face;      /* handle to face object */
81
82 int freetype_main() {
83     FT_Check(FT_Init_FreeType(&library));
84     _pause();
85     
86     /*char *fontdata;
87     int glyph_index;
88     short charcode;
89
90
91     FT_Check(FT_Init_FreeType(&library));
92
93     for(;;) {
94       
95         _pause();
96         FT_Check(FT_Set_Char_Size(face, 0, ((int)user_info[4]) * 64, 72, 72));
97         for(charcode = (int)user_info[2]; charcode <= (int)user_info[3]; charcode++) {
98
99             glyph_index = FT_Get_Char_Index(face, charcode);
100             FT_Check(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT));
101             FT_Check(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL));
102
103             user_info[5]  = (char*)face->glyph->bitmap.buffer;
104             user_info[6]  = (char*)face->glyph->bitmap.width;
105             user_info[7]  = (char*)face->glyph->bitmap.rows;
106             user_info[8]  = (char*)(face->size->metrics.ascender >> 6);
107             user_info[9]  = (char*)((-1 * face->size->metrics.descender) >> 6);
108             user_info[10] = (char*)(face->glyph->metrics.horiBearingY >> 6);
109             user_info[11] = (char*)(face->glyph->advance.x >> 6);
110
111         }
112     }*/
113 }
114
115 int load_font(char *buf, int length) __attribute__((section(".text")));
116 int load_font(char *buf, int length) {
117     if(face != NULL) FT_Check(FT_Done_Face(face));
118     face = NULL;
119     return FT_New_Memory_Face(library, buf, length, 0, &face);
120 }
121
122 // if the path is more than 16k chars long, we're screwed anyways...
123 static char path[1024 * 16];
124 static int pathlen = 0;
125 static int current_x;
126 static int current_y;
127
128 static void append(FT_Pos x, FT_Pos y) {
129     sprintf(path + pathlen, "%d,%d ", x - current_x, y - current_y);
130     pathlen += strlen(path + pathlen);
131 }
132 static int moveto(FT_Vector* to, void* user) {
133     if (pathlen > 0) {
134         path[pathlen++] = 'z';
135         path[pathlen++] = ' ';
136     }
137     path[pathlen++] = 'm';
138     path[pathlen++] = ' ';
139     append(to->x, to->y);
140     current_x = to->x; current_y = to->y;
141     return 0;
142 }
143 static int lineto(FT_Vector* to, void* user) {
144     path[pathlen++] = 'l';
145     path[pathlen++] = ' ';
146     append(to->x, to->y);
147     current_x = to->x; current_y = to->y;
148     return 0;
149 }
150 static int conicto(FT_Vector* control, FT_Vector*  to, void* user) {
151     path[pathlen++] = 'q';
152     path[pathlen++] = ' ';
153     append(control->x, control->y);
154     append(to->x, to->y);
155     current_x = to->x; current_y = to->y;
156     return 0;
157 }
158 static int cubicto(FT_Vector* control1, FT_Vector* control2, FT_Vector* to, void* user) {
159     path[pathlen++] = 'c';
160     path[pathlen++] = ' ';
161     append(control1->x, control1->y);
162     append(control2->x, control2->y);
163     append(to->x, to->y);
164     current_x = to->x; current_y = to->y;
165     return 0;
166 }
167 static FT_Outline_Funcs buildPath = { &moveto, &lineto, &conicto, &cubicto, 0, 0 };
168
169 int render(int charcode, int size) __attribute__((section(".text")));
170 int render(int charcode, int size) {
171     int glyph_index;
172     
173     FT_Check(FT_Set_Char_Size(face, 0, size * 64, 72, 72));
174     
175     glyph_index = FT_Get_Char_Index(face, charcode);
176     FT_Check(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_FORCE_AUTOHINT));
177     FT_Check(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL));
178     
179     user_info[0]  = (int)face->glyph->bitmap.buffer;
180     user_info[1]  = face->glyph->bitmap.width;
181     user_info[2]  = face->glyph->bitmap.rows;
182     user_info[3]  = face->size->metrics.ascender >> 6;
183     user_info[4]  = (-1 * face->size->metrics.descender) >> 6;
184     user_info[5] = face->glyph->metrics.horiBearingY >> 6;
185     user_info[6] = face->glyph->advance.x >> 6;
186
187     pathlen = 0; current_x = 0; current_y = 0;
188     FT_Outline_Decompose(&face->glyph->outline, &buildPath, NULL);
189     path[pathlen++] = 'z';
190     path[pathlen++] = ' ';
191     path[pathlen++] = 'm';
192     path[pathlen++] = ' ';
193     append(0, 0);
194     path[pathlen++] = ' ';
195     user_info[7] = (int)&path;
196     user_info[8] = pathlen;
197 }
198
199 // Kerning code; add back in later
200 /*
201 if (old_glyph_index != -1) {
202   if (FT_HAS_KERNING(face)) {
203     FT_Check(FT_Get_Kerning(face, old_glyph_index, glyph_index, 0, &kerning));
204     x += kerning.x >> 6;
205   } else {
206     x += face->glyph->advance.x >> 6;
207   }
208 }
209 old_glyph_index = glyph_index;
210 */