1 | /* |
2 | * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. Oracle designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Oracle in the LICENSE file that accompanied this code. |
10 | * |
11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
14 | * version 2 for more details (a copy is included in the LICENSE file that |
15 | * accompanied this code). |
16 | * |
17 | * You should have received a copy of the GNU General Public License version |
18 | * 2 along with this work; if not, write to the Free Software Foundation, |
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
20 | * |
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 | * or visit www.oracle.com if you need additional information or have any |
23 | * questions. |
24 | */ |
25 | |
26 | #include <stdio.h> |
27 | #include <string.h> |
28 | #include <stdlib.h> |
29 | |
30 | #include <ctype.h> |
31 | #include <sys/utsname.h> |
32 | |
33 | #include <jni.h> |
34 | #include <jni_util.h> |
35 | #include "fontscalerdefs.h" |
36 | #include "X11FontScaler.h" |
37 | |
38 | #ifndef HEADLESS |
39 | |
40 | #include <X11/Xlib.h> |
41 | #include <X11/Xutil.h> |
42 | #include <awt.h> |
43 | |
44 | static GC pixmapGC = 0; |
45 | static Pixmap pixmap = 0; |
46 | static Atom psAtom = 0; |
47 | static Atom fullNameAtom = 0; |
48 | static int pixmapWidth = 0; |
49 | static int pixmapHeight = 0; |
50 | |
51 | #define FONT_AWT_LOCK() \ |
52 | env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); \ |
53 | AWT_LOCK(); |
54 | |
55 | int CreatePixmapAndGC (int width, int height) |
56 | { |
57 | /* REMIND: use the actual screen, not the default screen */ |
58 | Window awt_defaultRoot = |
59 | RootWindow(awt_display, DefaultScreen(awt_display)); |
60 | |
61 | if (width < 100) { |
62 | width = 100; |
63 | } |
64 | if (height < 100) { |
65 | height = 100; |
66 | } |
67 | pixmapHeight = height; |
68 | pixmapWidth = width; |
69 | if (pixmap != 0) { |
70 | XFreePixmap (awt_display, pixmap); |
71 | } |
72 | if (pixmapGC != NULL) { |
73 | XFreeGC (awt_display, pixmapGC); |
74 | } |
75 | pixmap = XCreatePixmap (awt_display, awt_defaultRoot, pixmapWidth, |
76 | pixmapHeight, 1); |
77 | if (pixmap == 0) { |
78 | return BadAlloc; |
79 | } |
80 | pixmapGC = XCreateGC (awt_display, pixmap, 0, 0); |
81 | if (pixmapGC == NULL) { |
82 | return BadAlloc; |
83 | } |
84 | XFillRectangle (awt_display, pixmap, pixmapGC, 0, 0, pixmapWidth, |
85 | pixmapHeight); |
86 | XSetForeground (awt_display, pixmapGC, 1); |
87 | return Success; |
88 | } |
89 | |
90 | #ifdef DUMP_IMAGES |
91 | |
92 | static void dumpXImage(XImage *ximage) |
93 | { |
94 | int height = ximage->height; |
95 | int width = ximage->width; |
96 | int row; |
97 | int column; |
98 | |
99 | fprintf(stderr, "-------------------------------------------\n" ); |
100 | for (row = 0; row < height; ++row) { |
101 | for (column = 0; column < width; ++column) { |
102 | int pixel = ximage->f.get_pixel(ximage, column, row); |
103 | fprintf(stderr, (pixel == 0) ? " " : "XX" ); |
104 | } |
105 | fprintf(stderr, "\n" ); |
106 | } |
107 | fprintf(stderr, "-------------------------------------------\n" ); |
108 | } |
109 | |
110 | #endif |
111 | |
112 | #endif /* !HEADLESS */ |
113 | |
114 | JNIEXPORT int JNICALL AWTCountFonts(char* xlfd) { |
115 | #ifdef HEADLESS |
116 | return 0; |
117 | #else |
118 | char **names; |
119 | int count; |
120 | JNIEnv *env; |
121 | FONT_AWT_LOCK(); |
122 | names = XListFonts(awt_display, xlfd, 3, &count); |
123 | XFreeFontNames(names); |
124 | AWT_UNLOCK(); |
125 | return count; |
126 | #endif /* !HEADLESS */ |
127 | } |
128 | |
129 | JNIEXPORT void JNICALL AWTLoadFont(char* name, AWTFont *pReturn) { |
130 | JNIEnv *env; |
131 | *pReturn = NULL; |
132 | #ifndef HEADLESS |
133 | FONT_AWT_LOCK(); |
134 | *pReturn = (AWTFont)XLoadQueryFont(awt_display, name); |
135 | AWT_UNLOCK(); |
136 | #endif /* !HEADLESS */ |
137 | } |
138 | |
139 | JNIEXPORT void JNICALL AWTFreeFont(AWTFont font) { |
140 | #ifndef HEADLESS |
141 | JNIEnv *env; |
142 | FONT_AWT_LOCK(); |
143 | XFreeFont(awt_display, (XFontStruct *)font); |
144 | AWT_UNLOCK(); |
145 | #endif /* !HEADLESS */ |
146 | } |
147 | |
148 | JNIEXPORT unsigned JNICALL AWTFontMinByte1(AWTFont font) { |
149 | #ifdef HEADLESS |
150 | return 0; |
151 | #else |
152 | return ((XFontStruct *)font)->min_byte1; |
153 | #endif /* !HEADLESS */ |
154 | } |
155 | |
156 | JNIEXPORT unsigned JNICALL AWTFontMaxByte1(AWTFont font) { |
157 | #ifdef HEADLESS |
158 | return 0; |
159 | #else |
160 | return ((XFontStruct *)font)->max_byte1; |
161 | #endif /* !HEADLESS */ |
162 | } |
163 | |
164 | JNIEXPORT unsigned JNICALL AWTFontMinCharOrByte2(AWTFont font) { |
165 | #ifdef HEADLESS |
166 | return 0; |
167 | #else |
168 | return ((XFontStruct *)font)->min_char_or_byte2; |
169 | #endif /* !HEADLESS */ |
170 | } |
171 | |
172 | JNIEXPORT unsigned JNICALL AWTFontMaxCharOrByte2(AWTFont font) { |
173 | #ifdef HEADLESS |
174 | return 0; |
175 | #else |
176 | return ((XFontStruct *)font)->max_char_or_byte2; |
177 | #endif /* !HEADLESS */ |
178 | } |
179 | |
180 | JNIEXPORT unsigned JNICALL AWTFontDefaultChar(AWTFont font) { |
181 | #ifdef HEADLESS |
182 | return 0; |
183 | #else |
184 | return ((XFontStruct *)font)->default_char; |
185 | #endif /* !HEADLESS */ |
186 | } |
187 | |
188 | JNIEXPORT AWTChar JNICALL AWTFontPerChar(AWTFont font, int index) { |
189 | #ifdef HEADLESS |
190 | return NULL; |
191 | #else |
192 | XFontStruct *fXFont = (XFontStruct *)font; |
193 | XCharStruct *perChar = fXFont->per_char; |
194 | if (perChar == NULL) { |
195 | return NULL; |
196 | } |
197 | return (AWTChar)&(perChar[index]); |
198 | #endif /* !HEADLESS */ |
199 | } |
200 | |
201 | JNIEXPORT AWTChar JNICALL AWTFontMaxBounds(AWTFont font) { |
202 | #ifdef HEADLESS |
203 | return 0; |
204 | #else |
205 | return (AWTChar)&((XFontStruct *)font)->max_bounds; |
206 | #endif /* !HEADLESS */ |
207 | } |
208 | |
209 | |
210 | JNIEXPORT int JNICALL AWTFontAscent(AWTFont font) { |
211 | #ifdef HEADLESS |
212 | return 0; |
213 | #else |
214 | return ((XFontStruct *)font)->ascent; |
215 | #endif /* !HEADLESS */ |
216 | } |
217 | |
218 | |
219 | JNIEXPORT int JNICALL AWTFontDescent(AWTFont font) { |
220 | #ifdef HEADLESS |
221 | return 0; |
222 | #else |
223 | return ((XFontStruct *)font)->descent; |
224 | #endif /* !HEADLESS */ |
225 | } |
226 | |
227 | JNIEXPORT void JNICALL AWTFontTextExtents16(AWTFont font, |
228 | AWTChar2b* xChar, |
229 | AWTChar* overall) { |
230 | #ifndef HEADLESS |
231 | JNIEnv *env; |
232 | int ascent, descent, direction; |
233 | XFontStruct* xFont = (XFontStruct*)font; |
234 | XCharStruct* newChar = (XCharStruct*)malloc(sizeof(XCharStruct)); |
235 | *overall = (AWTChar)newChar; |
236 | /* There is a claim from the pre 1.5 source base that the info in the |
237 | * XFontStruct is flaky for 16 byte chars. This seems plausible as |
238 | * for info to be valid, that struct would need a large number of |
239 | * XCharStructs. But there's nothing in the X APIs which warns you of |
240 | * this. If it really is flaky you must question why there's an |
241 | * XTextExtents16 API call. Try XTextExtents16 for now and if it fails |
242 | * go back to XQueryTextExtents16 in this function. |
243 | * Indeed the metrics from the Solaris 9 JA font |
244 | * -ricoh-gothic-medium-r-normal--*-140-72-72-m-*-jisx0208.1983-0 |
245 | * do appear different so revert to the query api |
246 | */ |
247 | FONT_AWT_LOCK(); |
248 | XQueryTextExtents16(awt_display,xFont->fid, xChar, 1, |
249 | &direction, &ascent, &descent, newChar); |
250 | /* XTextExtents16(xFont, xChar, 1, &direction, &ascent, &descent, newChar); */ |
251 | AWT_UNLOCK(); |
252 | #endif /* !HEADLESS */ |
253 | } |
254 | |
255 | JNIEXPORT void JNICALL AWTFreeChar(AWTChar xChar) { |
256 | #ifndef HEADLESS |
257 | free(xChar); |
258 | #endif /* !HEADLESS */ |
259 | } |
260 | |
261 | JNIEXPORT jlong JNICALL AWTFontGenerateImage(AWTFont pFont, AWTChar2b* xChar) { |
262 | |
263 | #ifndef HEADLESS |
264 | |
265 | int width, height, direction, ascent, descent; |
266 | GlyphInfo *glyphInfo; |
267 | XFontStruct* xFont = (XFontStruct*)pFont; |
268 | XCharStruct xcs; |
269 | XImage *ximage; |
270 | int h, i, j, nbytes; |
271 | unsigned char *srcRow, *dstRow, *dstByte; |
272 | int wholeByteCount, remainingBitsCount; |
273 | unsigned int imageSize; |
274 | JNIEnv *env; |
275 | |
276 | FONT_AWT_LOCK(); |
277 | /* XTextExtents16(xFont, xChar, 1, &direction, &ascent, &descent, &xcs); */ |
278 | XQueryTextExtents16(awt_display,xFont->fid, xChar, 1, |
279 | &direction, &ascent, &descent, &xcs); |
280 | width = xcs.rbearing - xcs.lbearing; |
281 | height = xcs.ascent+xcs.descent; |
282 | imageSize = width*height; |
283 | |
284 | glyphInfo = (GlyphInfo*)malloc(sizeof(GlyphInfo)+imageSize); |
285 | glyphInfo->cellInfo = NULL; |
286 | glyphInfo->width = width; |
287 | glyphInfo->height = height; |
288 | glyphInfo->topLeftX = xcs.lbearing; |
289 | glyphInfo->topLeftY = -xcs.ascent; |
290 | glyphInfo->advanceX = xcs.width; |
291 | glyphInfo->advanceY = 0; |
292 | |
293 | if (imageSize == 0) { |
294 | glyphInfo->image = NULL; |
295 | AWT_UNLOCK(); |
296 | return (jlong)(uintptr_t)glyphInfo; |
297 | } else { |
298 | glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo); |
299 | } |
300 | |
301 | if ((pixmap == 0) || (width > pixmapWidth) || (height > pixmapHeight)) { |
302 | if (CreatePixmapAndGC(width, height) != Success) { |
303 | glyphInfo->image = NULL; |
304 | AWT_UNLOCK(); |
305 | return (jlong)(uintptr_t)glyphInfo; |
306 | } |
307 | } |
308 | |
309 | XSetFont(awt_display, pixmapGC, xFont->fid); |
310 | XSetForeground(awt_display, pixmapGC, 0); |
311 | XFillRectangle(awt_display, pixmap, pixmapGC, 0, 0, |
312 | pixmapWidth, pixmapHeight); |
313 | XSetForeground(awt_display, pixmapGC, 1); |
314 | XDrawString16(awt_display, pixmap, pixmapGC, |
315 | -xcs.lbearing, xcs.ascent, xChar, 1); |
316 | ximage = XGetImage(awt_display, pixmap, 0, 0, width, height, |
317 | AllPlanes, XYPixmap); |
318 | |
319 | if (ximage == NULL) { |
320 | glyphInfo->image = NULL; |
321 | AWT_UNLOCK(); |
322 | return (jlong)(uintptr_t)glyphInfo; |
323 | } |
324 | |
325 | #ifdef DUMP_IMAGES |
326 | dumpXImage(ximage); |
327 | #endif |
328 | |
329 | nbytes = ximage->bytes_per_line; |
330 | srcRow = (unsigned char*)ximage->data; |
331 | dstRow = (unsigned char*)glyphInfo->image; |
332 | wholeByteCount = width >> 3; |
333 | remainingBitsCount = width & 7; |
334 | |
335 | for (h=0; h<height; h++) { |
336 | const UInt8* src8 = srcRow; |
337 | UInt8 *dstByte = dstRow; |
338 | UInt32 srcValue; |
339 | |
340 | srcRow += nbytes; |
341 | dstRow += width; |
342 | |
343 | for (i = 0; i < wholeByteCount; i++) { |
344 | srcValue = *src8++; |
345 | for (j = 0; j < 8; j++) { |
346 | if (ximage->bitmap_bit_order == LSBFirst) { |
347 | *dstByte++ = (srcValue & 0x01) ? 0xFF : 0; |
348 | srcValue >>= 1; |
349 | } else { /* MSBFirst */ |
350 | *dstByte++ = (srcValue & 0x80) ? 0xFF : 0; |
351 | srcValue <<= 1; |
352 | } |
353 | } |
354 | } |
355 | if (remainingBitsCount) { |
356 | srcValue = *src8; |
357 | for (j = 0; j < remainingBitsCount; j++) { |
358 | if (ximage->bitmap_bit_order == LSBFirst) { |
359 | *dstByte++ = (srcValue & 0x01) ? 0xFF : 0; |
360 | srcValue >>= 1; |
361 | } else { /* MSBFirst */ |
362 | *dstByte++ = (srcValue & 0x80) ? 0xFF : 0; |
363 | srcValue <<= 1; |
364 | } |
365 | } |
366 | } |
367 | } |
368 | |
369 | XDestroyImage (ximage); |
370 | AWT_UNLOCK(); |
371 | return (jlong)(uintptr_t)glyphInfo; |
372 | #else |
373 | return (jlong)0; |
374 | #endif /* !HEADLESS */ |
375 | } |
376 | |
377 | JNIEXPORT short JNICALL AWTCharAdvance(AWTChar xChar) { |
378 | #ifdef HEADLESS |
379 | return 0; |
380 | #else |
381 | return ((XCharStruct *)xChar)->width; |
382 | #endif /* !HEADLESS */ |
383 | } |
384 | |
385 | JNIEXPORT short JNICALL AWTCharLBearing(AWTChar xChar) { |
386 | #ifdef HEADLESS |
387 | return 0; |
388 | #else |
389 | return ((XCharStruct *)xChar)->lbearing; |
390 | #endif /* !HEADLESS */ |
391 | } |
392 | |
393 | JNIEXPORT short JNICALL AWTCharRBearing(AWTChar xChar) { |
394 | #ifdef HEADLESS |
395 | return 0; |
396 | #else |
397 | return ((XCharStruct *)xChar)->rbearing; |
398 | #endif /* !HEADLESS */ |
399 | } |
400 | |
401 | JNIEXPORT short JNICALL AWTCharAscent(AWTChar xChar) { |
402 | #ifdef HEADLESS |
403 | return 0; |
404 | #else |
405 | return ((XCharStruct *)xChar)->ascent; |
406 | #endif /* !HEADLESS */ |
407 | } |
408 | |
409 | JNIEXPORT short JNICALL AWTCharDescent(AWTChar xChar) { |
410 | #ifdef HEADLESS |
411 | return 0; |
412 | #else |
413 | return ((XCharStruct *)xChar)->descent; |
414 | #endif /* !HEADLESS */ |
415 | } |
416 | |