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
44static GC pixmapGC = 0;
45static Pixmap pixmap = 0;
46static Atom psAtom = 0;
47static Atom fullNameAtom = 0;
48static int pixmapWidth = 0;
49static int pixmapHeight = 0;
50
51#define FONT_AWT_LOCK() \
52env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); \
53AWT_LOCK();
54
55int 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
92static 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
114JNIEXPORT 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
129JNIEXPORT 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
139JNIEXPORT 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
148JNIEXPORT unsigned JNICALL AWTFontMinByte1(AWTFont font) {
149#ifdef HEADLESS
150    return 0;
151#else
152    return ((XFontStruct *)font)->min_byte1;
153#endif /* !HEADLESS */
154}
155
156JNIEXPORT unsigned JNICALL AWTFontMaxByte1(AWTFont font) {
157#ifdef HEADLESS
158    return 0;
159#else
160    return ((XFontStruct *)font)->max_byte1;
161#endif /* !HEADLESS */
162}
163
164JNIEXPORT 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
172JNIEXPORT 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
180JNIEXPORT unsigned JNICALL AWTFontDefaultChar(AWTFont font) {
181#ifdef HEADLESS
182    return 0;
183#else
184    return ((XFontStruct *)font)->default_char;
185#endif /* !HEADLESS */
186}
187
188JNIEXPORT 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
201JNIEXPORT 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
210JNIEXPORT int JNICALL AWTFontAscent(AWTFont font) {
211#ifdef HEADLESS
212    return 0;
213#else
214    return ((XFontStruct *)font)->ascent;
215#endif /* !HEADLESS */
216}
217
218
219JNIEXPORT int JNICALL AWTFontDescent(AWTFont font) {
220#ifdef HEADLESS
221    return 0;
222#else
223    return ((XFontStruct *)font)->descent;
224#endif /* !HEADLESS */
225}
226
227JNIEXPORT 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
255JNIEXPORT void JNICALL AWTFreeChar(AWTChar xChar) {
256#ifndef HEADLESS
257    free(xChar);
258#endif /* !HEADLESS */
259}
260
261JNIEXPORT 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
377JNIEXPORT short JNICALL AWTCharAdvance(AWTChar xChar) {
378#ifdef HEADLESS
379    return 0;
380#else
381    return ((XCharStruct *)xChar)->width;
382#endif /* !HEADLESS */
383}
384
385JNIEXPORT short JNICALL AWTCharLBearing(AWTChar xChar) {
386#ifdef HEADLESS
387    return 0;
388#else
389    return ((XCharStruct *)xChar)->lbearing;
390#endif /* !HEADLESS */
391}
392
393JNIEXPORT short JNICALL AWTCharRBearing(AWTChar xChar) {
394#ifdef HEADLESS
395    return 0;
396#else
397    return ((XCharStruct *)xChar)->rbearing;
398#endif /* !HEADLESS */
399}
400
401JNIEXPORT short JNICALL AWTCharAscent(AWTChar xChar) {
402#ifdef HEADLESS
403    return 0;
404#else
405    return ((XCharStruct *)xChar)->ascent;
406#endif /* !HEADLESS */
407}
408
409JNIEXPORT short JNICALL AWTCharDescent(AWTChar xChar) {
410#ifdef HEADLESS
411    return 0;
412#else
413    return ((XCharStruct *)xChar)->descent;
414#endif /* !HEADLESS */
415}
416