1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/lib/DtTerm/TermPrim/TermPrimLineDraw.c
chase dd68514e4f Remove hpversion.h from repository
This patch removes hpversion.h from the repository, this also untangles a
lot of ifdef mess. This closes bug CDExc19524.
2018-10-06 17:00:38 -06:00

650 lines
19 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* *
* (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
* (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
* (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
* (c) Copyright 1993, 1994, 1996 Novell, Inc. *
* (c) Copyright 1996 Digital Equipment Corporation. *
* (c) Copyright 1996 FUJITSU LIMITED. *
* (c) Copyright 1996 Hitachi. *
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <Xm/Xm.h>
#include "TermPrimLineFontP.h"
#include "TermPrimLineDrawP.h"
#include "TermPrimDebug.h"
#include "TermPrimP.h"
/****************************************************************************
*
* This module is used to implement the line drawing functionality for
* hpterm. It implements a primitive (simple?) font scaling engine that
* converts a set of rectangles, lines, and "stipples" to a line drawing
* font. The font is stored as a single plane pixmap and is rendered by
* performing a copy plane to the target drawable.
*
* To increase the performance, fonts are not free'ed when the reference
* count hits zero. Rather, they are free'ed if the reference count has
* hit zero and a new font is created with different parameters.
*
***************************************************************************/
static LineDrawFontData lineDrawFontDataHead = (LineDrawFontData) 0;
static LineDrawFont lineDrawFontHead = (LineDrawFont) 0;
/* static int numLineDrawFonts = 0; */
static void
ScaleCharacter(
#ifdef USE_PIXMAPS
GC gc, Pixmap bitmap,
ScaledBitmapInfo renderInfo, GlyphInfo glyph,
int width, int height
#else /* USE_PIXMAPS */
ScaledCharInfo renderInfo, GlyphInfo glyph, int width, int height
#endif /* USE_PIXMAPS */
)
{
int j;
#ifdef USE_PIXMAPS
cellPositionType cellX;
cellPositionType cellX;
Pixmap pixmap;
#else /* USE_PIXMAPS */
int k;
int numLines;
#endif /* USE_PIXMAPS */
#ifdef USE_PIXMAPS
/* calculate position of pixmap into which we will draw the glyph...
*/
cellX = (i % 16) * width;
cellY = (i / 16) * height;
renderInfo->cellX = cellX;
renderInfo->cellY = cellY;
#else /* USE_PIXMAPS */
/* malloc storage for the line segments, rectangles, stipples...
*/
/* count the number of lines... */
for (j = 0, numLines = 0; j < glyph->numLines; j++) {
numLines += glyph->lines[j].width;
}
if (numLines > 0) {
/* malloc the line storage... */
renderInfo->segs = (XSegment *)
XtRealloc((void *) renderInfo->segs,
numLines * sizeof(XSegment));
}
renderInfo->numSegs = numLines;
/* rectangles... */
if (glyph->numRects > 0) {
/* malloc the rectangle storage... */
renderInfo->rects = (XRectangle *)
XtRealloc((void *) renderInfo->rects,
glyph->numRects * sizeof(XRectangle));
}
renderInfo->numRects = glyph->numRects;
/* stipples... */
if (glyph->numStipples > 0) {
/* malloc the stipple storage... */
renderInfo->stipples = (XRectangle *)
XtRealloc((void *) renderInfo->stipples,
glyph->numStipples * sizeof(XRectangle));
}
renderInfo->numStipples = glyph->numStipples;
#endif /* USE_PIXMAPS */
/* draw the lines...
*/
#ifndef USE_PIXMAPS
/* reset the counter... */
numLines = 0;
#endif /* USE_PIXMAPS */
/* lines
*/
for (j = 0; j < glyph->numLines; j++) {
/* draw the line segment / scale the line segment... */
int x1;
int x2;
int y1;
int y2;
DebugF('l', 0, fprintf(stderr,
">> line data: x1=%d%+d y1=%d%+d x2=%d%+d y2=%d%+d width=%d",
glyph->lines[j].x1,
glyph->lines[j].x1Offset,
glyph->lines[j].y1,
glyph->lines[j].y1Offset,
glyph->lines[j].x2,
glyph->lines[j].x2Offset,
glyph->lines[j].y2,
glyph->lines[j].y2Offset,
glyph->lines[j].width));
/* scale x1 and x2 to our width... */
x1 = ((width - 1) * glyph->lines[j].x1) / 100;
x2 = ((width - 1) * glyph->lines[j].x2) / 100;
/* scale y1 and y2 to our height... */
y1 = ((height - 1) * glyph->lines[j].y1) / 100;
y2 = ((height - 1) * glyph->lines[j].y2) / 100;
/* add offsets... */
x1 += glyph->lines[j].x1Offset;
x2 += glyph->lines[j].x2Offset;
y1 += glyph->lines[j].y1Offset;
y2 += glyph->lines[j].y2Offset;
#ifdef USE_PIXMAPS
/* add in the line width... */
if (x1 == x2) {
x1 -= (glyph->lines[j].width - 1) / 2;
x2 += glyph->lines[j].width - 1 - (glyph->lines[j].width - 1) / 2;
}
/* add in the line width... */
if (y1 == y2) {
y1 -= (glyph->lines[j].width - 1) / 2;
y2 += glyph->lines[j].width - 1 - (glyph->lines[j].width - 1) / 2;
}
DebugF('l', 0, fprintf(stderr,
">> line: x=%d y=%d width=%d height=%d",
x1, y1, x2 - x1 + 1, y2 - y1 + 1));
/* draw the line (actually, fill the rectangle)... */
(void) XFillRectangle(d, /* display */
pixmap, /* drawable */
gc, /* GC */
cellX + x1, /* x */
cellY + y1, /* y */
x2 - x1 + 1, /* width */
y2 - y1 + 1); /* height */
#else /* USE_PIXMAPS */
if ((x1 == x2) && (y1 != y2)) {
/* vertical lines... */
for (k = 0; k < glyph->lines[j].width; k++) {
renderInfo->segs[numLines + k].x1 =
renderInfo->segs[numLines + k].x2 =
x1 - (glyph->lines[j].width / 2) + k;
renderInfo->segs[numLines + k].y1 = y1;
renderInfo->segs[numLines + k].y2 = y2;
}
} else if ((y1 == y2) && (x1 != x2)) {
/* horizontal lines... */
for (k = 0; k < glyph->lines[j].width ; k++) {
renderInfo->segs[numLines + k].y1 =
renderInfo->segs[numLines + k].y2 =
y2 - (glyph->lines[j].width / 2) + k;
renderInfo->segs[numLines + k].x1 = x1;
renderInfo->segs[numLines + k].x2 = x2;
}
} else {
for (k = 0; k < glyph->lines[j].width; k++) {
renderInfo->segs[numLines + k].y1 =
renderInfo->segs[numLines + k].y2 =
y2 - (glyph->lines[j].width / 2) + k;
renderInfo->segs[numLines + k].x1 = x1 -
glyph->lines[j].width / 2;
renderInfo->segs[numLines + k].x2 = x2 +
glyph->lines[j].width / 2;
}
}
numLines += glyph->lines[j].width;
}
#endif /* USE_PIXMAPS */
/* rectangles...
*/
for (j = 0; j < glyph->numRects; j++) {
/* draw / stipple the rectangles... */
int x1;
int x2;
int y1;
int y2;
/* scale x1 and x2 to our width... */
x1 = ((width - 1) * glyph->rects[j].x1) / 100;
x2 = ((width - 1) * glyph->rects[j].x2) / 100;
/* scale y1 and y2 to our height... */
y1 = ((height - 1) * glyph->rects[j].y1) / 100;
y2 = ((height - 1) * glyph->rects[j].y2) / 100;
/* add offsets... */
x1 += glyph->rects[j].x1Offset;
x2 += glyph->rects[j].x2Offset;
y1 += glyph->rects[j].y1Offset;
y2 += glyph->rects[j].y2Offset;
#ifdef USE_PIXMAPS
DebugF('l', 0, fprintf(stderr,
">> rect: x=%d y=%d width=%d height=%d",
x1, y1, x2 - x1 + 1, y2 - y1 + 1));
/* fill the rectangle... */
(void) XFillRectangle(d, /* display */
pixmap, /* drawable */
gc, /* GC */
cellX + x1, /* x */
cellY + y1, /* y */
x2 - x1 + 1, /* width */
y2 - y1 + 1); /* height */
#else /* USE_PIXMAPS */
renderInfo->rects[j].x = x1;
renderInfo->rects[j].y = y1;
renderInfo->rects[j].width = x2 - x1 + 1;
renderInfo->rects[j].height = y2 - y1 + 1;
#endif /* USE_PIXMAPS */
}
/* stipple in the rectangle...
*/
for (j = 0; j < glyph->numStipples; j++) {
/* stipple the rectangle... */
int x1;
int x2;
int y1;
int y2;
int stippleSize;
#ifdef USE_PIXMAPS
int xIndex;
int yIndex;
#endif /* USE_PIXMAPS */
/* scale x1 and x2 to our width... */
x1 = ((width - 1) * glyph->stipples[j].x1) / 100;
x2 = ((width - 1) * glyph->stipples[j].x2) / 100;
/* scale y1 and y2 to our height... */
y1 = ((height - 1) * glyph->stipples[j].y1) / 100;
y2 = ((height - 1) * glyph->stipples[j].y2) / 100;
stippleSize = glyph->stipples[j].width;
/* add offsets... */
x1 += glyph->stipples[j].x1Offset;
x2 += glyph->stipples[j].x2Offset;
y1 += glyph->stipples[j].y1Offset;
y2 += glyph->stipples[j].y2Offset;
#ifdef USE_PIXMAPS
/* fill in the area... */
for (yIndex = y1; yIndex < y2; yIndex += stippleSize) {
for (xIndex = x1; xIndex < x2; xIndex += stippleSize) {
if (!(((xIndex / stippleSize) % 2) ^
((yIndex / stippleSize) % 2))) {
/* fill this rectangle... */
DebugF('l', 0, fprintf(stderr,
">> stipple: x=%d y=%d width=%d height=%d",
xIndex, yIndex,
(stippleSize <= (x2 - xIndex)) ? stippleSize :
x2 - xIndex,
(stippleSize <= (y2 - yIndex)) ? stippleSize :
y2 - yIndex));
(void) XFillRectangle(d, /* display */
pixmap, /* drawable */
gc, /* GC */
cellX + xIndex, /* x */
cellY + yIndex, /* y */
(stippleSize <= (x2 - xIndex)) ? stippleSize :
x2 - xIndex,
/* width */
(stippleSize <= (y2 - yIndex)) ? stippleSize :
y2 - yIndex);
/* height */
}
}
}
#endif /* USE_PIXMAPS */
}
/* mark this character as completed... */
#ifdef USE_PIXMAPS
renderInfo->scaled = True;
#else /* USE_PIXMAPS */
renderInfo->scaled = True;
#endif /* USE_PIXMAPS */
}
static short *
GetLineDrawFontIndex(GlyphInfo glyphInfo, int numGlyphs)
{
LineDrawFontData lineDrawFontData;
int i;
int j;
for (lineDrawFontData = lineDrawFontDataHead; lineDrawFontData;
lineDrawFontData = lineDrawFontData->next) {
if ((lineDrawFontData->glyphInfo == glyphInfo) &&
lineDrawFontData->numGlyphs == numGlyphs) {
return(lineDrawFontData->lineDrawIndex);
}
}
/* no match. Insert one at the head of the list and fill it out...
*/
lineDrawFontData = (LineDrawFontData) XtMalloc(sizeof(LineDrawFontDataRec));
lineDrawFontData->next = lineDrawFontDataHead;
lineDrawFontDataHead = lineDrawFontData;
lineDrawFontData->glyphInfo = glyphInfo;
lineDrawFontData->numGlyphs = numGlyphs;
/* clear out the array... */
for (i = 0; i < (sizeof(lineDrawFontData->lineDrawIndex) /
sizeof(lineDrawFontData->lineDrawIndex[0])); i++) {
lineDrawFontData->lineDrawIndex[i] = -1;
}
/* fill up the array... */
for (i = 0; i < numGlyphs; i++) {
for (j = 0; glyphInfo[i].chars[j] > 0; j++) {
lineDrawFontData->lineDrawIndex[glyphInfo[i].chars[j] % 256] = i;
}
}
return(lineDrawFontData->lineDrawIndex);
}
LineDrawFont
_DtTermPrimLineDrawCreateFont(Widget w, GlyphInfo glyphInfo, int numGlyphs,
int width, int ascent, int descent)
{
DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
struct termData *tpd = tw->term.tpd;
int fontNumber;
LineDrawFont lineDrawFont;
int i;
int height = ascent + descent;
#ifdef USE_PIXMAPS
GC gc;
Pixmap pixmap;
#endif /* USE_PIXMAPS */
_DtTermProcessLock();
/* let's look for a line draw font that is already made...
*/
for (lineDrawFont = lineDrawFontHead; lineDrawFont;
lineDrawFont = lineDrawFont->next) {
if ((lineDrawFont->fontValid) &&
(lineDrawFont->width == width) &&
(lineDrawFont->height == height) &&
(lineDrawFont->ascent == ascent) &&
(lineDrawFont->display == XtDisplay(w)) &&
(lineDrawFont->glyphInfo == glyphInfo) &&
(lineDrawFont->numGlyphs == numGlyphs)) {
/* we found a match...
*/
/* bump the reference count... */
(void) lineDrawFont->refCount++;
/* and return this "font"... */
_DtTermProcessUnlock();
return (lineDrawFont);
}
}
/* no match -- we will have to build the font...
*/
/* look for a free slot... */
for (lineDrawFont = lineDrawFontHead; lineDrawFont;
lineDrawFont = lineDrawFont->next) {
if ((lineDrawFont->refCount == 0) &&
(lineDrawFont->glyphInfo == glyphInfo) &&
(lineDrawFont->numGlyphs == numGlyphs)) {
/* found a free slot... */
/* free any valid but unused font in this slot... */
if (lineDrawFont->fontValid) {
#ifdef USE_PIXMAPS
(void) XFreePixmap(lineDrawFont->display,
/* Display */
lineDrawFont->pixmap); /* drawable */
#endif /* USE_PIXMAPS */
lineDrawFont->fontValid = False;
}
break;
}
}
/* did we hit the end of the linked list... */
if (!lineDrawFont) {
/* add a new entry to the head of the linked list... */
lineDrawFont = (LineDrawFont)
XtMalloc(sizeof(LineDrawFontRec));
(void) memset(lineDrawFont, '\0', sizeof(LineDrawFontRec));
lineDrawFont->next = lineDrawFontHead;
lineDrawFontHead = lineDrawFont;
}
lineDrawFont->refCount = 1;
lineDrawFont->fontValid = True;
lineDrawFont->width = width;
lineDrawFont->height = height;
lineDrawFont->ascent = ascent;
lineDrawFont->width = width;
lineDrawFont->display = XtDisplay(w);
lineDrawFont->glyphInfo = glyphInfo;
lineDrawFont->numGlyphs = numGlyphs;
lineDrawFont->glyphIndex = GetLineDrawFontIndex(glyphInfo, numGlyphs);
#ifdef USE_PIXMAPS
/* malloc the cell position for this font (if necessary)... */
if (!lineDrawFont->scaledBitmapInfo) {
lineDrawFont->scaledBitmapInfo = (ScaledBitmapInfo)
XtMalloc(lineDrawFont->numGlyphs * sizeof(ScaledBitmapInfoRec));
/* initialize it... */
(void) memset(lineDrawFont->scaledBitmapInfo, '\0',
lineDrawFont->numGlyphs * sizeof(scaledBitmapInfo));
} else {
/* mark all the characters in the old font as unscaled... */
for (i = 0; i < lineDrawFont->numGlyphs; i++) {
lineDrawFont->scaledBitmapInfo[i].scaled = False;
}
}
#else /* USE_PIXMAPS */
/* malloc the line, rectangle, stipple storage (if necessary)... */
if (!lineDrawFont->scaledCharInfo) {
lineDrawFont->scaledCharInfo = (ScaledCharInfo)
XtMalloc(lineDrawFont->numGlyphs * sizeof(ScaledCharInfoRec));
(void) memset(lineDrawFont->scaledCharInfo, '\0',
lineDrawFont->numGlyphs * sizeof(ScaledCharInfoRec));
} else {
/* mark all the characters in the old font as unscaled... */
for (i = 0; i < lineDrawFont->numGlyphs; i++) {
lineDrawFont->scaledCharInfo[i].scaled = False;
}
}
#endif /* USE_PIXMAPS */
#ifdef USE_PIXMAPS
/* create a pixmap that is 16 characters wide and
* lineDrawFont->numGlyphs / 16 characters high...
*/
pixmap = XCreatePixmap(d,
/* Display */
DefaultRootWindow(d), /* reference window */
width * 16, /* width */
(lineDrawFont->numGlyphs + 15) / 16 * (height),
/* height */
1); /* planes */
lineDrawFont->pixmap = pixmap;
/* we need a GC...
*/
gc = XCreateGC(d, /* Display */
pixmap, /* drawable */
(unsigned long) (0), /* value mask */
(XGCValues *) 0); /* values */
/* clear the pixmap... */
(void) XSetForeground(d, gc, 0);
(void) XFillRectangle(d, /* display */
pixmap, /* drawable */
gc, /* GC */
0, /* x */
0, /* y */
width * 16, /* width */
(lineDrawFont->numGlyphs + 15) / 16 * (height));
/* height */
/* reset the GC so we can fill in the lines and rectangles... */
(void) XSetForeground(d, gc, 1);
#endif /* USE_PIXMAPS */
_DtTermProcessUnlock();
return(lineDrawFont);
}
void
_DtTermPrimLineDrawFreeFont(LineDrawFont lineDrawFont)
{
_DtTermProcessLock();
/* perform a sanity check... */
if (lineDrawFont->refCount <= 0) {
_DtTermProcessUnlock();
return;
}
/* decrement the reference count... */
(void) lineDrawFont->refCount--;
/* we will free the storage if this font is used... */
_DtTermProcessUnlock();
return;
}
void
_DtTermPrimLineDrawImageString(Display *display, Drawable d,
LineDrawFont lineDrawFont,
GC gc, GC clearGC, int x, int y, unsigned char *string, int width)
{
int glyph;
#ifndef USE_PIXMAPS
XSegment segs[20];
XRectangle rects[20];
int i;
#endif /* USE_PIXMAPS */
_DtTermProcessLock();
if (!lineDrawFont || (lineDrawFont->refCount < 0)) {
_DtTermProcessUnlock();
return;
}
#ifndef USE_PIXMAPS
/* clear the area... */
(void) XFillRectangle(display, /* Display */
d, /* Window */
clearGC, /* GC */
x, /* x */
y - lineDrawFont->ascent, /* y */
lineDrawFont->width * width, /* width */
lineDrawFont->height); /* height */
#endif /* USE_PIXMAPS */
/* render the characters... */
for (; width > 0; width--, string++) {
/* look up glyph through the glyph table... */
/* check for valid glyph... */
glyph = lineDrawFont->glyphIndex[*string];
/* if it is invalid, then let's default to space... */
if (glyph < 0)
glyph = lineDrawFont->glyphIndex[' '];
/* if it is still invalid, then let's skip this character... */
if (glyph < 0) {
x += lineDrawFont->width;
continue;
}
#ifdef USE_PIXMAPS
/* render this character... */
(void) XCopyPlane(display, /* Display */
lineDrawFont->pixmap, /* src */
d, /* dest */
gc, /* GC */
lineDrawFont->cellX[glyph], /* src x */
lineDrawFont->cellY[glyph], /* src y */
lineDrawFont->width, /* width */
lineDrawFont->height, /* height */
x, /* dest x */
y - lineDrawFont->ascent, /* dest y */
1); /* plane */
#else /* USE_PIXMAPS */
if (!lineDrawFont->scaledCharInfo[glyph].scaled) {
/* first time, scale this character... */
(void) ScaleCharacter(&(lineDrawFont->scaledCharInfo[glyph]),
&(lineDrawFont->glyphInfo[glyph]), lineDrawFont->width, lineDrawFont->height);
}
if (lineDrawFont->scaledCharInfo[glyph].numSegs > 0) {
for (i = 0; i < lineDrawFont->scaledCharInfo[glyph].numSegs; i++) {
segs[i].x1 = x + lineDrawFont->scaledCharInfo[glyph].segs[i].x1;
segs[i].x2 = x + lineDrawFont->scaledCharInfo[glyph].segs[i].x2;
segs[i].y1 =
y + lineDrawFont->scaledCharInfo[glyph].segs[i].y1 -
lineDrawFont->ascent;
segs[i].y2 =
y + lineDrawFont->scaledCharInfo[glyph].segs[i].y2 -
lineDrawFont->ascent;
}
(void) XDrawSegments(display, /* Display */
d, /* dest */
gc, /* GC */
segs, /* segments */
lineDrawFont->scaledCharInfo[glyph].numSegs);
/* num segs */
}
if (lineDrawFont->scaledCharInfo[glyph].numRects > 0) {
for (i = 0; i < lineDrawFont->scaledCharInfo[glyph].numRects; i++) {
rects[i].x = x + lineDrawFont->scaledCharInfo[glyph].rects[i].x;
rects[i].y =
y + lineDrawFont->scaledCharInfo[glyph].rects[i].y -
lineDrawFont->ascent;
rects[i].width =
lineDrawFont->scaledCharInfo[glyph].rects[i].width;
rects[i].height =
lineDrawFont->scaledCharInfo[glyph].rects[i].height;
}
(void) XFillRectangles(display, /* Display */
d, /* dest */
gc, /* GC */
rects, /* rectangles */
lineDrawFont->scaledCharInfo[glyph].numRects);
/* num rects */
}
#endif /* USE_PIXMAPS */
/* slide over one character... */
x += lineDrawFont->width;
}
_DtTermProcessUnlock();
return;
}