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 
CreatePixmapAndGC(int width,int height)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 
dumpXImage(XImage * ximage)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 
AWTCountFonts(char * xlfd)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 
AWTLoadFont(char * name,AWTFont * pReturn)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 
AWTFreeFont(AWTFont font)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 
AWTFontMinByte1(AWTFont font)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 
AWTFontMaxByte1(AWTFont font)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 
AWTFontMinCharOrByte2(AWTFont font)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 
AWTFontMaxCharOrByte2(AWTFont font)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 
AWTFontDefaultChar(AWTFont font)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 
AWTFontPerChar(AWTFont font,int index)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 
AWTFontMaxBounds(AWTFont font)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 
AWTFontAscent(AWTFont font)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 
AWTFontDescent(AWTFont font)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 
AWTFontTextExtents16(AWTFont font,AWTChar2b * xChar,AWTChar * overall)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 
AWTFreeChar(AWTChar xChar)255 JNIEXPORT void JNICALL AWTFreeChar(AWTChar xChar) {
256 #ifndef HEADLESS
257     free(xChar);
258 #endif /* !HEADLESS */
259 }
260 
AWTFontGenerateImage(AWTFont pFont,AWTChar2b * xChar)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 
277     FONT_AWT_LOCK();
278 /*     XTextExtents16(xFont, xChar, 1, &direction, &ascent, &descent, &xcs); */
279     XQueryTextExtents16(awt_display,xFont->fid, xChar, 1,
280                         &direction, &ascent, &descent, &xcs);
281     width = xcs.rbearing - xcs.lbearing;
282     height = xcs.ascent+xcs.descent;
283     imageSize = width*height;
284     glyphInfo = (GlyphInfo*)malloc(sizeof(GlyphInfo)+imageSize);
285     if (glyphInfo == NULL) {
286         AWT_UNLOCK();
287         return (jlong)(uintptr_t)NULL;
288     }
289     glyphInfo->cellInfo = NULL;
290     glyphInfo->width = width;
291     glyphInfo->height = height;
292     glyphInfo->topLeftX = xcs.lbearing;
293     glyphInfo->topLeftY = -xcs.ascent;
294     glyphInfo->advanceX = xcs.width;
295     glyphInfo->advanceY = 0;
296 
297     if (imageSize == 0) {
298         glyphInfo->image = NULL;
299         AWT_UNLOCK();
300         return (jlong)(uintptr_t)glyphInfo;
301     } else {
302         glyphInfo->image = (unsigned char*)glyphInfo+sizeof(GlyphInfo);
303     }
304 
305     if ((pixmap == 0) || (width > pixmapWidth) || (height > pixmapHeight)) {
306         if (CreatePixmapAndGC(width, height) != Success) {
307             glyphInfo->image = NULL;
308             AWT_UNLOCK();
309             return (jlong)(uintptr_t)glyphInfo;
310         }
311     }
312 
313     XSetFont(awt_display, pixmapGC, xFont->fid);
314     XSetForeground(awt_display, pixmapGC, 0);
315     XFillRectangle(awt_display, pixmap, pixmapGC, 0, 0,
316                    pixmapWidth, pixmapHeight);
317     XSetForeground(awt_display, pixmapGC, 1);
318     XDrawString16(awt_display, pixmap, pixmapGC,
319                   -xcs.lbearing, xcs.ascent, xChar, 1);
320     ximage = XGetImage(awt_display, pixmap, 0, 0, width, height,
321                        AllPlanes, XYPixmap);
322 
323     if (ximage == NULL) {
324         glyphInfo->image = NULL;
325         AWT_UNLOCK();
326         return (jlong)(uintptr_t)glyphInfo;
327     }
328 
329 #ifdef DUMP_IMAGES
330     dumpXImage(ximage);
331 #endif
332 
333     nbytes =  ximage->bytes_per_line;
334     srcRow = (unsigned char*)ximage->data;
335     dstRow = (unsigned char*)glyphInfo->image;
336     wholeByteCount = width >> 3;
337     remainingBitsCount = width & 7;
338 
339     for (h=0; h<height; h++) {
340         const UInt8* src8 = srcRow;
341         UInt8 *dstByte = dstRow;
342         UInt32 srcValue;
343 
344         srcRow += nbytes;
345         dstRow += width;
346 
347         for (i = 0; i < wholeByteCount; i++) {
348             srcValue = *src8++;
349             for (j = 0; j < 8; j++) {
350                 if (ximage->bitmap_bit_order == LSBFirst) {
351                     *dstByte++ = (srcValue & 0x01) ? 0xFF : 0;
352                     srcValue >>= 1;
353                 } else {                /* MSBFirst */
354                     *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
355                     srcValue <<= 1;
356                 }
357             }
358         }
359         if (remainingBitsCount) {
360             srcValue = *src8;
361             for (j = 0; j < remainingBitsCount; j++) {
362                 if (ximage->bitmap_bit_order == LSBFirst) {
363                     *dstByte++ = (srcValue & 0x01) ? 0xFF : 0;
364                     srcValue >>= 1;
365                 } else {                /* MSBFirst */
366                     *dstByte++ = (srcValue & 0x80) ? 0xFF : 0;
367                     srcValue <<= 1;
368                 }
369             }
370         }
371     }
372 
373     XDestroyImage (ximage);
374     AWT_UNLOCK();
375     return (jlong)(uintptr_t)glyphInfo;
376 #else
377     return (jlong)0;
378 #endif /* !HEADLESS */
379 }
380 
AWTCharAdvance(AWTChar xChar)381 JNIEXPORT short JNICALL AWTCharAdvance(AWTChar xChar) {
382 #ifdef HEADLESS
383     return 0;
384 #else
385     return ((XCharStruct *)xChar)->width;
386 #endif /* !HEADLESS */
387 }
388 
AWTCharLBearing(AWTChar xChar)389 JNIEXPORT short JNICALL AWTCharLBearing(AWTChar xChar) {
390 #ifdef HEADLESS
391     return 0;
392 #else
393     return ((XCharStruct *)xChar)->lbearing;
394 #endif /* !HEADLESS */
395 }
396 
AWTCharRBearing(AWTChar xChar)397 JNIEXPORT short JNICALL AWTCharRBearing(AWTChar xChar) {
398 #ifdef HEADLESS
399     return 0;
400 #else
401     return ((XCharStruct *)xChar)->rbearing;
402 #endif /* !HEADLESS */
403 }
404 
AWTCharAscent(AWTChar xChar)405 JNIEXPORT short JNICALL AWTCharAscent(AWTChar xChar) {
406 #ifdef HEADLESS
407     return 0;
408 #else
409     return ((XCharStruct *)xChar)->ascent;
410 #endif /* !HEADLESS */
411 }
412 
AWTCharDescent(AWTChar xChar)413 JNIEXPORT short JNICALL AWTCharDescent(AWTChar xChar) {
414 #ifdef HEADLESS
415     return 0;
416 #else
417     return ((XCharStruct *)xChar)->descent;
418 #endif /* !HEADLESS */
419 }
420