1 /* 2 * Copyright (c) 2001, 2005, 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 "GlyphImageRef.h" 27 28 #ifdef HEADLESS 29 #include "SurfaceData.h" 30 #else 31 #include "X11SurfaceData.h" 32 #include "GraphicsPrimitiveMgr.h" 33 #endif /* !HEADLESS */ 34 #include <jlong.h> 35 36 #define TEXT_BM_WIDTH 1024 37 #define TEXT_BM_HEIGHT 32 38 39 #ifndef HEADLESS 40 41 static jboolean checkPixmap(JNIEnv *env, AwtGraphicsConfigDataPtr cData) 42 { 43 XImage *img; 44 int image_size; 45 Window root; 46 47 if (cData->monoImage == NULL) { 48 img = XCreateImage(awt_display, NULL, 1, XYBitmap, 0, 0, 49 TEXT_BM_WIDTH, TEXT_BM_HEIGHT, 32, 0); 50 if (img != NULL) { 51 image_size = img->bytes_per_line * TEXT_BM_HEIGHT; 52 // assert(BM_W and BM_H are not large enough to overflow); 53 img->data = (char *) malloc(image_size); 54 if (img->data == NULL) { 55 XFree(img); 56 } else { 57 // Force same bit/byte ordering 58 img->bitmap_bit_order = img->byte_order; 59 cData->monoImage = img; 60 } 61 } 62 if (cData->monoImage == NULL) { 63 JNU_ThrowOutOfMemoryError(env, "Cannot allocate bitmap for text"); 64 return JNI_FALSE; 65 } 66 } 67 if (cData->monoPixmap == 0 || 68 cData->monoPixmapGC == NULL || 69 cData->monoPixmapWidth != TEXT_BM_WIDTH || 70 cData->monoPixmapHeight != TEXT_BM_HEIGHT) 71 { 72 if (cData->monoPixmap != 0) { 73 XFreePixmap(awt_display, cData->monoPixmap); 74 cData->monoPixmap = 0; 75 } 76 if (cData->monoPixmapGC != NULL) { 77 XFreeGC(awt_display, cData->monoPixmapGC); 78 cData->monoPixmapGC = 0; 79 } 80 root = RootWindow(awt_display, cData->awt_visInfo.screen); 81 cData->monoPixmap = XCreatePixmap(awt_display, root, 82 TEXT_BM_WIDTH, TEXT_BM_HEIGHT, 1); 83 if (cData->monoPixmap == 0) { 84 JNU_ThrowOutOfMemoryError(env, "Cannot allocate pixmap for text"); 85 return JNI_FALSE; 86 } 87 cData->monoPixmapGC = XCreateGC(awt_display, cData->monoPixmap, 88 0, NULL); 89 if (cData->monoPixmapGC == NULL) { 90 XFreePixmap(awt_display, cData->monoPixmap); 91 cData->monoPixmap = 0; 92 JNU_ThrowOutOfMemoryError(env, "Cannot allocate pixmap for text"); 93 return JNI_FALSE; 94 } 95 XSetForeground(awt_display, cData->monoPixmapGC, 1); 96 XSetBackground(awt_display, cData->monoPixmapGC, 0); 97 cData->monoPixmapWidth = TEXT_BM_WIDTH; 98 cData->monoPixmapHeight = TEXT_BM_HEIGHT; 99 } 100 return JNI_TRUE; 101 } 102 103 static void FillBitmap(XImage *theImage, 104 ImageRef *glyphs, jint totalGlyphs, 105 jint clipLeft, jint clipTop, 106 jint clipRight, jint clipBottom) 107 { 108 int glyphCounter; 109 int scan = theImage->bytes_per_line; 110 int y, left, top, right, bottom, width, height; 111 jubyte *pPix; 112 const jubyte *pixels; 113 unsigned int rowBytes; 114 115 pPix = (jubyte *) theImage->data; 116 glyphCounter = ((clipRight - clipLeft) + 7) >> 3; 117 for (y = clipTop; y < clipBottom; y++) { 118 memset(pPix, 0, glyphCounter); 119 pPix += scan; 120 } 121 122 for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) { 123 pixels = (const jubyte *)glyphs[glyphCounter].pixels; 124 if (!pixels) { 125 continue; 126 } 127 rowBytes = glyphs[glyphCounter].width; 128 left = glyphs[glyphCounter].x; 129 top = glyphs[glyphCounter].y; 130 width = glyphs[glyphCounter].width; 131 height = glyphs[glyphCounter].height; 132 133 /* if any clipping required, modify parameters now */ 134 right = left + width; 135 bottom = top + height; 136 if (left < clipLeft) { 137 pixels += clipLeft - left; 138 left = clipLeft; 139 } 140 if (top < clipTop) { 141 pixels += (clipTop - top) * rowBytes; 142 top = clipTop; 143 } 144 if (right > clipRight) { 145 right = clipRight; 146 } 147 if (bottom > clipBottom) { 148 bottom = clipBottom; 149 } 150 if (right <= left || bottom <= top) { 151 continue; 152 } 153 width = right - left; 154 height = bottom - top; 155 top -= clipTop; 156 left -= clipLeft; 157 pPix = ((jubyte *) theImage->data) + (left >> 3) + top * scan; 158 left &= 0x07; 159 if (theImage->bitmap_bit_order == MSBFirst) { 160 left = 0x80 >> left; 161 do { 162 int x = 0, bx = 0; 163 int pix = pPix[0]; 164 int bit = left; 165 do { 166 if (bit == 0) { 167 pPix[bx] = (jubyte) pix; 168 pix = pPix[++bx]; 169 bit = 0x80; 170 } 171 if (pixels[x]) { 172 pix |= bit; 173 } 174 bit >>= 1; 175 } while (++x < width); 176 pPix[bx] = (jubyte) pix; 177 pPix += scan; 178 pixels += rowBytes; 179 } while (--height > 0); 180 } else { 181 left = 1 << left; 182 do { 183 int x = 0, bx = 0; 184 int pix = pPix[0]; 185 int bit = left; 186 do { 187 if ((bit >> 8) != 0) { 188 pPix[bx] = (jubyte) pix; 189 pix = pPix[++bx]; 190 bit = 1; 191 } 192 if (pixels[x]) { 193 pix |= bit; 194 } 195 bit <<= 1; 196 } while (++x < width); 197 pPix[bx] = (jubyte) pix; 198 pPix += scan; 199 pixels += rowBytes; 200 } while (--height > 0); 201 } 202 } 203 } 204 #endif /* !HEADLESS */ 205 206 JNIEXPORT void JNICALL 207 AWTDrawGlyphList(JNIEnv *env, jobject xtr, 208 jlong dstData, jlong gc, 209 SurfaceDataBounds *bounds, ImageRef *glyphs, jint totalGlyphs) 210 { 211 #ifndef HEADLESS 212 GC xgc, theGC; 213 XImage *theImage; 214 Pixmap thePixmap; 215 XGCValues xgcv; 216 int scan, screen; 217 AwtGraphicsConfigDataPtr cData; 218 X11SDOps *xsdo = (X11SDOps *)jlong_to_ptr(dstData); 219 jint cx1, cy1, cx2, cy2; 220 221 if (xsdo == NULL) { 222 return; 223 } 224 225 xgc = (GC)gc; 226 if (xgc == NULL) { 227 return; 228 } 229 230 screen = xsdo->configData->awt_visInfo.screen; 231 cData = getDefaultConfig(screen); 232 if (!checkPixmap(env, cData)) { 233 return; 234 } 235 theImage = cData->monoImage; 236 thePixmap = cData->monoPixmap; 237 theGC = cData->monoPixmapGC; 238 239 scan = theImage->bytes_per_line; 240 241 xgcv.fill_style = FillStippled; 242 xgcv.stipple = thePixmap; 243 xgcv.ts_x_origin = bounds->x1; 244 xgcv.ts_y_origin = bounds->y1; 245 XChangeGC(awt_display, xgc, 246 GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin, 247 &xgcv); 248 249 cy1 = bounds->y1; 250 while (cy1 < bounds->y2) { 251 cy2 = cy1 + TEXT_BM_HEIGHT; 252 if (cy2 > bounds->y2) cy2 = bounds->y2; 253 254 cx1 = bounds->x1; 255 while (cx1 < bounds->x2) { 256 cx2 = cx1 + TEXT_BM_WIDTH; 257 if (cx2 > bounds->x2) cx2 = bounds->x2; 258 259 FillBitmap(theImage, 260 glyphs, 261 totalGlyphs, 262 cx1, cy1, cx2, cy2); 263 264 // NOTE: Since we are tiling around by BM_W, BM_H offsets 265 // and thePixmap is BM_W x BM_H, we do not have to move 266 // the TSOrigin at each step since the stipple repeats 267 // every BM_W, BM_H units 268 XPutImage(awt_display, thePixmap, theGC, theImage, 269 0, 0, 0, 0, cx2 - cx1, cy2 - cy1); 270 /* MGA on Linux doesn't pick up the new stipple image data, 271 * probably because it caches the image as a hardware pixmap 272 * and doesn't update it when the pixmap image data is changed. 273 * So if the loop is executed more than once, update the GC 274 * which triggers the required behaviour. This extra XChangeGC 275 * call only happens on large or rotated text so isn't a 276 * significant new overhead.. 277 * This code needs to execute on a Solaris client too, in case 278 * we are remote displaying to a MGA. 279 */ 280 if (cy1 != bounds->y1 || cx1 != bounds->x1) { 281 XChangeGC(awt_display, xgc, GCStipple, &xgcv); 282 } 283 284 XFillRectangle(awt_display, xsdo->drawable, xgc, 285 cx1, cy1, cx2 - cx1, cy2 - cy1); 286 287 cx1 = cx2; 288 } 289 290 cy1 = cy2; 291 } 292 XSetFillStyle(awt_display, xgc, FillSolid); 293 294 X11SD_DirectRenderNotify(env, xsdo); 295 #endif /* !HEADLESS */ 296 }