0N/A/*
2362N/A * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include "GlyphImageRef.h"
0N/A
0N/A#ifdef HEADLESS
0N/A#include "SurfaceData.h"
0N/A#else
0N/A#include "X11SurfaceData.h"
0N/A#include "GraphicsPrimitiveMgr.h"
0N/A#endif /* !HEADLESS */
0N/A#include <jlong.h>
0N/A
0N/A#define TEXT_BM_WIDTH 1024
0N/A#define TEXT_BM_HEIGHT 32
0N/A
0N/A#ifndef HEADLESS
0N/A
0N/Astatic jboolean checkPixmap(JNIEnv *env, AwtGraphicsConfigDataPtr cData)
0N/A{
0N/A XImage *img;
0N/A int image_size;
0N/A Window root;
0N/A
0N/A if (cData->monoImage == NULL) {
0N/A img = XCreateImage(awt_display, NULL, 1, XYBitmap, 0, 0,
0N/A TEXT_BM_WIDTH, TEXT_BM_HEIGHT, 32, 0);
0N/A if (img != NULL) {
0N/A image_size = img->bytes_per_line * TEXT_BM_HEIGHT;
0N/A // assert(BM_W and BM_H are not large enough to overflow);
0N/A img->data = (char *) malloc(image_size);
0N/A if (img->data == NULL) {
0N/A XFree(img);
0N/A } else {
0N/A // Force same bit/byte ordering
0N/A img->bitmap_bit_order = img->byte_order;
0N/A cData->monoImage = img;
0N/A }
0N/A }
0N/A if (cData->monoImage == NULL) {
0N/A JNU_ThrowOutOfMemoryError(env, "Cannot allocate bitmap for text");
0N/A return JNI_FALSE;
0N/A }
0N/A }
0N/A if (cData->monoPixmap == 0 ||
0N/A cData->monoPixmapGC == NULL ||
0N/A cData->monoPixmapWidth != TEXT_BM_WIDTH ||
0N/A cData->monoPixmapHeight != TEXT_BM_HEIGHT)
0N/A {
0N/A if (cData->monoPixmap != 0) {
0N/A XFreePixmap(awt_display, cData->monoPixmap);
0N/A cData->monoPixmap = 0;
0N/A }
0N/A if (cData->monoPixmapGC != NULL) {
0N/A XFreeGC(awt_display, cData->monoPixmapGC);
0N/A cData->monoPixmapGC = 0;
0N/A }
0N/A root = RootWindow(awt_display, cData->awt_visInfo.screen);
0N/A cData->monoPixmap = XCreatePixmap(awt_display, root,
0N/A TEXT_BM_WIDTH, TEXT_BM_HEIGHT, 1);
0N/A if (cData->monoPixmap == 0) {
0N/A JNU_ThrowOutOfMemoryError(env, "Cannot allocate pixmap for text");
0N/A return JNI_FALSE;
0N/A }
0N/A cData->monoPixmapGC = XCreateGC(awt_display, cData->monoPixmap,
0N/A 0, NULL);
0N/A if (cData->monoPixmapGC == NULL) {
0N/A XFreePixmap(awt_display, cData->monoPixmap);
0N/A cData->monoPixmap = 0;
0N/A JNU_ThrowOutOfMemoryError(env, "Cannot allocate pixmap for text");
0N/A return JNI_FALSE;
0N/A }
0N/A XSetForeground(awt_display, cData->monoPixmapGC, 1);
0N/A XSetBackground(awt_display, cData->monoPixmapGC, 0);
0N/A cData->monoPixmapWidth = TEXT_BM_WIDTH;
0N/A cData->monoPixmapHeight = TEXT_BM_HEIGHT;
0N/A }
0N/A return JNI_TRUE;
0N/A}
0N/A
0N/Astatic void FillBitmap(XImage *theImage,
0N/A ImageRef *glyphs, jint totalGlyphs,
0N/A jint clipLeft, jint clipTop,
0N/A jint clipRight, jint clipBottom)
0N/A{
0N/A int glyphCounter;
0N/A int scan = theImage->bytes_per_line;
0N/A int y, left, top, right, bottom, width, height;
0N/A jubyte *pPix;
0N/A const jubyte *pixels;
0N/A unsigned int rowBytes;
0N/A
0N/A pPix = (jubyte *) theImage->data;
0N/A glyphCounter = ((clipRight - clipLeft) + 7) >> 3;
0N/A for (y = clipTop; y < clipBottom; y++) {
0N/A memset(pPix, 0, glyphCounter);
0N/A pPix += scan;
0N/A }
0N/A
0N/A for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) {
0N/A pixels = (const jubyte *)glyphs[glyphCounter].pixels;
0N/A if (!pixels) {
0N/A continue;
0N/A }
0N/A rowBytes = glyphs[glyphCounter].width;
0N/A left = glyphs[glyphCounter].x;
0N/A top = glyphs[glyphCounter].y;
0N/A width = glyphs[glyphCounter].width;
0N/A height = glyphs[glyphCounter].height;
0N/A
0N/A /* if any clipping required, modify parameters now */
0N/A right = left + width;
0N/A bottom = top + height;
0N/A if (left < clipLeft) {
0N/A pixels += clipLeft - left;
0N/A left = clipLeft;
0N/A }
0N/A if (top < clipTop) {
0N/A pixels += (clipTop - top) * rowBytes;
0N/A top = clipTop;
0N/A }
0N/A if (right > clipRight) {
0N/A right = clipRight;
0N/A }
0N/A if (bottom > clipBottom) {
0N/A bottom = clipBottom;
0N/A }
0N/A if (right <= left || bottom <= top) {
0N/A continue;
0N/A }
0N/A width = right - left;
0N/A height = bottom - top;
0N/A top -= clipTop;
0N/A left -= clipLeft;
0N/A pPix = ((jubyte *) theImage->data) + (left >> 3) + top * scan;
0N/A left &= 0x07;
0N/A if (theImage->bitmap_bit_order == MSBFirst) {
0N/A left = 0x80 >> left;
0N/A do {
0N/A int x = 0, bx = 0;
0N/A int pix = pPix[0];
0N/A int bit = left;
0N/A do {
0N/A if (bit == 0) {
0N/A pPix[bx] = (jubyte) pix;
0N/A pix = pPix[++bx];
0N/A bit = 0x80;
0N/A }
0N/A if (pixels[x]) {
0N/A pix |= bit;
0N/A }
0N/A bit >>= 1;
0N/A } while (++x < width);
0N/A pPix[bx] = (jubyte) pix;
0N/A pPix += scan;
0N/A pixels += rowBytes;
0N/A } while (--height > 0);
0N/A } else {
0N/A left = 1 << left;
0N/A do {
0N/A int x = 0, bx = 0;
0N/A int pix = pPix[0];
0N/A int bit = left;
0N/A do {
0N/A if ((bit >> 8) != 0) {
0N/A pPix[bx] = (jubyte) pix;
0N/A pix = pPix[++bx];
0N/A bit = 1;
0N/A }
0N/A if (pixels[x]) {
0N/A pix |= bit;
0N/A }
0N/A bit <<= 1;
0N/A } while (++x < width);
0N/A pPix[bx] = (jubyte) pix;
0N/A pPix += scan;
0N/A pixels += rowBytes;
0N/A } while (--height > 0);
0N/A }
0N/A }
0N/A}
0N/A#endif /* !HEADLESS */
0N/A
0N/AJNIEXPORT void JNICALL
0N/AAWTDrawGlyphList(JNIEnv *env, jobject xtr,
0N/A jlong dstData, jlong gc,
0N/A SurfaceDataBounds *bounds, ImageRef *glyphs, jint totalGlyphs)
0N/A{
0N/A#ifndef HEADLESS
0N/A GC xgc, theGC;
0N/A XImage *theImage;
0N/A Pixmap thePixmap;
0N/A XGCValues xgcv;
0N/A int scan, screen;
0N/A AwtGraphicsConfigDataPtr cData;
0N/A X11SDOps *xsdo = (X11SDOps *)jlong_to_ptr(dstData);
0N/A jint cx1, cy1, cx2, cy2;
0N/A
0N/A if (xsdo == NULL) {
0N/A return;
0N/A }
0N/A
0N/A xgc = (GC)gc;
0N/A if (xgc == NULL) {
0N/A return;
0N/A }
0N/A
0N/A screen = xsdo->configData->awt_visInfo.screen;
0N/A cData = getDefaultConfig(screen);
0N/A if (!checkPixmap(env, cData)) {
0N/A return;
0N/A }
0N/A theImage = cData->monoImage;
0N/A thePixmap = cData->monoPixmap;
0N/A theGC = cData->monoPixmapGC;
0N/A
0N/A scan = theImage->bytes_per_line;
0N/A
0N/A xgcv.fill_style = FillStippled;
0N/A xgcv.stipple = thePixmap;
0N/A xgcv.ts_x_origin = bounds->x1;
0N/A xgcv.ts_y_origin = bounds->y1;
0N/A XChangeGC(awt_display, xgc,
0N/A GCFillStyle | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin,
0N/A &xgcv);
0N/A
0N/A cy1 = bounds->y1;
0N/A while (cy1 < bounds->y2) {
0N/A cy2 = cy1 + TEXT_BM_HEIGHT;
0N/A if (cy2 > bounds->y2) cy2 = bounds->y2;
0N/A
0N/A cx1 = bounds->x1;
0N/A while (cx1 < bounds->x2) {
0N/A cx2 = cx1 + TEXT_BM_WIDTH;
0N/A if (cx2 > bounds->x2) cx2 = bounds->x2;
0N/A
0N/A FillBitmap(theImage,
0N/A glyphs,
0N/A totalGlyphs,
0N/A cx1, cy1, cx2, cy2);
0N/A
0N/A // NOTE: Since we are tiling around by BM_W, BM_H offsets
0N/A // and thePixmap is BM_W x BM_H, we do not have to move
0N/A // the TSOrigin at each step since the stipple repeats
0N/A // every BM_W, BM_H units
0N/A XPutImage(awt_display, thePixmap, theGC, theImage,
0N/A 0, 0, 0, 0, cx2 - cx1, cy2 - cy1);
0N/A /* MGA on Linux doesn't pick up the new stipple image data,
0N/A * probably because it caches the image as a hardware pixmap
0N/A * and doesn't update it when the pixmap image data is changed.
0N/A * So if the loop is executed more than once, update the GC
0N/A * which triggers the required behaviour. This extra XChangeGC
0N/A * call only happens on large or rotated text so isn't a
0N/A * significant new overhead..
0N/A * This code needs to execute on a Solaris client too, in case
0N/A * we are remote displaying to a MGA.
0N/A */
0N/A if (cy1 != bounds->y1 || cx1 != bounds->x1) {
0N/A XChangeGC(awt_display, xgc, GCStipple, &xgcv);
0N/A }
0N/A
0N/A XFillRectangle(awt_display, xsdo->drawable, xgc,
0N/A cx1, cy1, cx2 - cx1, cy2 - cy1);
0N/A
0N/A cx1 = cx2;
0N/A }
0N/A
0N/A cy1 = cy2;
0N/A }
0N/A XSetFillStyle(awt_display, xgc, FillSolid);
0N/A
0N/A X11SD_DirectRenderNotify(env, xsdo);
0N/A#endif /* !HEADLESS */
0N/A}