2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 #ifdef VERBOSE_REV_INFO
25 static char rcs_id[] = "$XConsortium: TermPrimLineDraw.c /main/1 1996/04/21 19:17:48 drk $";
26 #endif /* VERBOSE_REV_INFO */
30 * (c) Copyright 1993, 1994, 1996 Hewlett-Packard Company *
31 * (c) Copyright 1993, 1994, 1996 International Business Machines Corp. *
32 * (c) Copyright 1993, 1994, 1996 Sun Microsystems, Inc. *
33 * (c) Copyright 1993, 1994, 1996 Novell, Inc. *
34 * (c) Copyright 1996 Digital Equipment Corporation. *
35 * (c) Copyright 1996 FUJITSU LIMITED. *
36 * (c) Copyright 1996 Hitachi. *
43 #include "TermPrimLineFontP.h"
44 #include "TermPrimLineDrawP.h"
45 #include "TermPrimDebug.h"
46 #include "TermPrimP.h"
48 /****************************************************************************
50 * This module is used to implement the line drawing functionality for
51 * hpterm. It implements a primitive (simple?) font scaling engine that
52 * converts a set of rectangles, lines, and "stipples" to a line drawing
53 * font. The font is stored as a single plane pixmap and is rendered by
54 * performing a copy plane to the target drawable.
56 * To increase the performance, fonts are not free'ed when the reference
57 * count hits zero. Rather, they are free'ed if the reference count has
58 * hit zero and a new font is created with different parameters.
60 ***************************************************************************/
62 static LineDrawFontData lineDrawFontDataHead = (LineDrawFontData) 0;
63 static LineDrawFont lineDrawFontHead = (LineDrawFont) 0;
64 /* static int numLineDrawFonts = 0; */
70 ScaledBitmapInfo renderInfo, GlyphInfo glyph,
72 #else /* USE_PIXMAPS */
73 ScaledCharInfo renderInfo, GlyphInfo glyph, int width, int height
74 #endif /* USE_PIXMAPS */
79 cellPositionType cellX;
80 cellPositionType cellX;
82 #else /* USE_PIXMAPS */
85 #endif /* USE_PIXMAPS */
88 /* calculate position of pixmap into which we will draw the glyph...
90 cellX = (i % 16) * width;
91 cellY = (i / 16) * height;
92 renderInfo->cellX = cellX;
93 renderInfo->cellY = cellY;
94 #else /* USE_PIXMAPS */
95 /* malloc storage for the line segments, rectangles, stipples...
97 /* count the number of lines... */
98 for (j = 0, numLines = 0; j < glyph->numLines; j++) {
99 numLines += glyph->lines[j].width;
102 /* malloc the line storage... */
103 renderInfo->segs = (XSegment *)
104 XtRealloc((void *) renderInfo->segs,
105 numLines * sizeof(XSegment));
107 renderInfo->numSegs = numLines;
110 if (glyph->numRects > 0) {
111 /* malloc the rectangle storage... */
112 renderInfo->rects = (XRectangle *)
113 XtRealloc((void *) renderInfo->rects,
114 glyph->numRects * sizeof(XRectangle));
116 renderInfo->numRects = glyph->numRects;
119 if (glyph->numStipples > 0) {
120 /* malloc the stipple storage... */
121 renderInfo->stipples = (XRectangle *)
122 XtRealloc((void *) renderInfo->stipples,
123 glyph->numStipples * sizeof(XRectangle));
125 renderInfo->numStipples = glyph->numStipples;
126 #endif /* USE_PIXMAPS */
131 /* reset the counter... */
133 #endif /* USE_PIXMAPS */
137 for (j = 0; j < glyph->numLines; j++) {
138 /* draw the line segment / scale the line segment... */
144 DebugF('l', 0, fprintf(stderr,
145 ">> line data: x1=%d%+d y1=%d%+d x2=%d%+d y2=%d%+d width=%d",
147 glyph->lines[j].x1Offset,
149 glyph->lines[j].y1Offset,
151 glyph->lines[j].x2Offset,
153 glyph->lines[j].y2Offset,
154 glyph->lines[j].width));
156 /* scale x1 and x2 to our width... */
157 x1 = ((width - 1) * glyph->lines[j].x1) / 100;
158 x2 = ((width - 1) * glyph->lines[j].x2) / 100;
160 /* scale y1 and y2 to our height... */
161 y1 = ((height - 1) * glyph->lines[j].y1) / 100;
162 y2 = ((height - 1) * glyph->lines[j].y2) / 100;
165 x1 += glyph->lines[j].x1Offset;
166 x2 += glyph->lines[j].x2Offset;
167 y1 += glyph->lines[j].y1Offset;
168 y2 += glyph->lines[j].y2Offset;
171 /* add in the line width... */
173 x1 -= (glyph->lines[j].width - 1) / 2;
174 x2 += glyph->lines[j].width - 1 - (glyph->lines[j].width - 1) / 2;
177 /* add in the line width... */
179 y1 -= (glyph->lines[j].width - 1) / 2;
180 y2 += glyph->lines[j].width - 1 - (glyph->lines[j].width - 1) / 2;
183 DebugF('l', 0, fprintf(stderr,
184 ">> line: x=%d y=%d width=%d height=%d",
185 x1, y1, x2 - x1 + 1, y2 - y1 + 1));
186 /* draw the line (actually, fill the rectangle)... */
187 (void) XFillRectangle(d, /* display */
188 pixmap, /* drawable */
192 x2 - x1 + 1, /* width */
193 y2 - y1 + 1); /* height */
194 #else /* USE_PIXMAPS */
195 if ((x1 == x2) && (y1 != y2)) {
196 /* vertical lines... */
197 for (k = 0; k < glyph->lines[j].width; k++) {
198 renderInfo->segs[numLines + k].x1 =
199 renderInfo->segs[numLines + k].x2 =
200 x1 - (glyph->lines[j].width / 2) + k;
201 renderInfo->segs[numLines + k].y1 = y1;
202 renderInfo->segs[numLines + k].y2 = y2;
204 } else if ((y1 == y2) && (x1 != x2)) {
205 /* horizontal lines... */
206 for (k = 0; k < glyph->lines[j].width ; k++) {
207 renderInfo->segs[numLines + k].y1 =
208 renderInfo->segs[numLines + k].y2 =
209 y2 - (glyph->lines[j].width / 2) + k;
210 renderInfo->segs[numLines + k].x1 = x1;
211 renderInfo->segs[numLines + k].x2 = x2;
214 for (k = 0; k < glyph->lines[j].width; k++) {
215 renderInfo->segs[numLines + k].y1 =
216 renderInfo->segs[numLines + k].y2 =
217 y2 - (glyph->lines[j].width / 2) + k;
218 renderInfo->segs[numLines + k].x1 = x1 -
219 glyph->lines[j].width / 2;
220 renderInfo->segs[numLines + k].x2 = x2 +
221 glyph->lines[j].width / 2;
225 numLines += glyph->lines[j].width;
227 #endif /* USE_PIXMAPS */
231 for (j = 0; j < glyph->numRects; j++) {
232 /* draw / stipple the rectangles... */
238 /* scale x1 and x2 to our width... */
239 x1 = ((width - 1) * glyph->rects[j].x1) / 100;
240 x2 = ((width - 1) * glyph->rects[j].x2) / 100;
242 /* scale y1 and y2 to our height... */
243 y1 = ((height - 1) * glyph->rects[j].y1) / 100;
244 y2 = ((height - 1) * glyph->rects[j].y2) / 100;
247 x1 += glyph->rects[j].x1Offset;
248 x2 += glyph->rects[j].x2Offset;
249 y1 += glyph->rects[j].y1Offset;
250 y2 += glyph->rects[j].y2Offset;
253 DebugF('l', 0, fprintf(stderr,
254 ">> rect: x=%d y=%d width=%d height=%d",
255 x1, y1, x2 - x1 + 1, y2 - y1 + 1));
256 /* fill the rectangle... */
257 (void) XFillRectangle(d, /* display */
258 pixmap, /* drawable */
262 x2 - x1 + 1, /* width */
263 y2 - y1 + 1); /* height */
264 #else /* USE_PIXMAPS */
265 renderInfo->rects[j].x = x1;
266 renderInfo->rects[j].y = y1;
267 renderInfo->rects[j].width = x2 - x1 + 1;
268 renderInfo->rects[j].height = y2 - y1 + 1;
269 #endif /* USE_PIXMAPS */
272 /* stipple in the rectangle...
274 for (j = 0; j < glyph->numStipples; j++) {
275 /* stipple the rectangle... */
284 #endif /* USE_PIXMAPS */
286 /* scale x1 and x2 to our width... */
287 x1 = ((width - 1) * glyph->stipples[j].x1) / 100;
288 x2 = ((width - 1) * glyph->stipples[j].x2) / 100;
290 /* scale y1 and y2 to our height... */
291 y1 = ((height - 1) * glyph->stipples[j].y1) / 100;
292 y2 = ((height - 1) * glyph->stipples[j].y2) / 100;
294 stippleSize = glyph->stipples[j].width;
297 x1 += glyph->stipples[j].x1Offset;
298 x2 += glyph->stipples[j].x2Offset;
299 y1 += glyph->stipples[j].y1Offset;
300 y2 += glyph->stipples[j].y2Offset;
303 /* fill in the area... */
304 for (yIndex = y1; yIndex < y2; yIndex += stippleSize) {
305 for (xIndex = x1; xIndex < x2; xIndex += stippleSize) {
306 if (!(((xIndex / stippleSize) % 2) ^
307 ((yIndex / stippleSize) % 2))) {
308 /* fill this rectangle... */
309 DebugF('l', 0, fprintf(stderr,
310 ">> stipple: x=%d y=%d width=%d height=%d",
312 (stippleSize <= (x2 - xIndex)) ? stippleSize :
314 (stippleSize <= (y2 - yIndex)) ? stippleSize :
316 (void) XFillRectangle(d, /* display */
317 pixmap, /* drawable */
319 cellX + xIndex, /* x */
320 cellY + yIndex, /* y */
321 (stippleSize <= (x2 - xIndex)) ? stippleSize :
324 (stippleSize <= (y2 - yIndex)) ? stippleSize :
330 #endif /* USE_PIXMAPS */
333 /* mark this character as completed... */
335 renderInfo->scaled = True;
336 #else /* USE_PIXMAPS */
337 renderInfo->scaled = True;
338 #endif /* USE_PIXMAPS */
342 GetLineDrawFontIndex(GlyphInfo glyphInfo, int numGlyphs)
344 LineDrawFontData lineDrawFontData;
348 for (lineDrawFontData = lineDrawFontDataHead; lineDrawFontData;
349 lineDrawFontData = lineDrawFontData->next) {
350 if ((lineDrawFontData->glyphInfo == glyphInfo) &&
351 lineDrawFontData->numGlyphs == numGlyphs) {
352 return(lineDrawFontData->lineDrawIndex);
356 /* no match. Insert one at the head of the list and fill it out...
358 lineDrawFontData = (LineDrawFontData) XtMalloc(sizeof(LineDrawFontDataRec));
359 lineDrawFontData->next = lineDrawFontDataHead;
360 lineDrawFontDataHead = lineDrawFontData;
361 lineDrawFontData->glyphInfo = glyphInfo;
362 lineDrawFontData->numGlyphs = numGlyphs;
363 /* clear out the array... */
364 for (i = 0; i < (sizeof(lineDrawFontData->lineDrawIndex) /
365 sizeof(lineDrawFontData->lineDrawIndex[0])); i++) {
366 lineDrawFontData->lineDrawIndex[i] = -1;
369 /* fill up the array... */
370 for (i = 0; i < numGlyphs; i++) {
371 for (j = 0; glyphInfo[i].chars[j] > 0; j++) {
372 lineDrawFontData->lineDrawIndex[glyphInfo[i].chars[j] % 256] = i;
375 return(lineDrawFontData->lineDrawIndex);
379 _DtTermPrimLineDrawCreateFont(Widget w, GlyphInfo glyphInfo, int numGlyphs,
380 int width, int ascent, int descent)
382 DtTermPrimitiveWidget tw = (DtTermPrimitiveWidget) w;
383 struct termData *tpd = tw->term.tpd;
385 LineDrawFont lineDrawFont;
387 int height = ascent + descent;
391 #endif /* USE_PIXMAPS */
393 _DtTermProcessLock();
394 /* let's look for a line draw font that is already made...
396 for (lineDrawFont = lineDrawFontHead; lineDrawFont;
397 lineDrawFont = lineDrawFont->next) {
398 if ((lineDrawFont->fontValid) &&
399 (lineDrawFont->width == width) &&
400 (lineDrawFont->height == height) &&
401 (lineDrawFont->ascent == ascent) &&
402 (lineDrawFont->display == XtDisplay(w)) &&
403 (lineDrawFont->glyphInfo == glyphInfo) &&
404 (lineDrawFont->numGlyphs == numGlyphs)) {
405 /* we found a match...
407 /* bump the reference count... */
408 (void) lineDrawFont->refCount++;
409 /* and return this "font"... */
410 _DtTermProcessUnlock();
411 return (lineDrawFont);
415 /* no match -- we will have to build the font...
417 /* look for a free slot... */
418 for (lineDrawFont = lineDrawFontHead; lineDrawFont;
419 lineDrawFont = lineDrawFont->next) {
420 if ((lineDrawFont->refCount == 0) &&
421 (lineDrawFont->glyphInfo == glyphInfo) &&
422 (lineDrawFont->numGlyphs == numGlyphs)) {
423 /* found a free slot... */
424 /* free any valid but unused font in this slot... */
425 if (lineDrawFont->fontValid) {
427 (void) XFreePixmap(lineDrawFont->display,
429 lineDrawFont->pixmap); /* drawable */
430 #endif /* USE_PIXMAPS */
431 lineDrawFont->fontValid = False;
437 /* did we hit the end of the linked list... */
439 /* add a new entry to the head of the linked list... */
440 lineDrawFont = (LineDrawFont)
441 XtMalloc(sizeof(LineDrawFontRec));
442 (void) memset(lineDrawFont, '\0', sizeof(LineDrawFontRec));
443 lineDrawFont->next = lineDrawFontHead;
444 lineDrawFontHead = lineDrawFont;
447 lineDrawFont->refCount = 1;
448 lineDrawFont->fontValid = True;
449 lineDrawFont->width = width;
450 lineDrawFont->height = height;
451 lineDrawFont->ascent = ascent;
452 lineDrawFont->width = width;
453 lineDrawFont->display = XtDisplay(w);
454 lineDrawFont->glyphInfo = glyphInfo;
455 lineDrawFont->numGlyphs = numGlyphs;
456 lineDrawFont->glyphIndex = GetLineDrawFontIndex(glyphInfo, numGlyphs);
459 /* malloc the cell position for this font (if necessary)... */
460 if (!lineDrawFont->scaledBitmapInfo) {
461 lineDrawFont->scaledBitmapInfo = (ScaledBitmapInfo)
462 XtMalloc(lineDrawFont->numGlyphs * sizeof(ScaledBitmapInfoRec));
463 /* initialize it... */
464 (void) memset(lineDrawFont->scaledBitmapInfo, '\0',
465 lineDrawFont->numGlyphs * sizeof(scaledBitmapInfo));
467 /* mark all the characters in the old font as unscaled... */
468 for (i = 0; i < lineDrawFont->numGlyphs; i++) {
469 lineDrawFont->scaledBitmapInfo[i].scaled = False;
472 #else /* USE_PIXMAPS */
473 /* malloc the line, rectangle, stipple storage (if necessary)... */
474 if (!lineDrawFont->scaledCharInfo) {
475 lineDrawFont->scaledCharInfo = (ScaledCharInfo)
476 XtMalloc(lineDrawFont->numGlyphs * sizeof(ScaledCharInfoRec));
477 (void) memset(lineDrawFont->scaledCharInfo, '\0',
478 lineDrawFont->numGlyphs * sizeof(ScaledCharInfoRec));
480 /* mark all the characters in the old font as unscaled... */
481 for (i = 0; i < lineDrawFont->numGlyphs; i++) {
482 lineDrawFont->scaledCharInfo[i].scaled = False;
485 #endif /* USE_PIXMAPS */
488 /* create a pixmap that is 16 characters wide and
489 * lineDrawFont->numGlyphs / 16 characters high...
491 pixmap = XCreatePixmap(d,
493 DefaultRootWindow(d), /* reference window */
494 width * 16, /* width */
495 (lineDrawFont->numGlyphs + 15) / 16 * (height),
498 lineDrawFont->pixmap = pixmap;
502 gc = XCreateGC(d, /* Display */
503 pixmap, /* drawable */
504 (unsigned long) (0), /* value mask */
505 (XGCValues *) 0); /* values */
507 /* clear the pixmap... */
508 (void) XSetForeground(d, gc, 0);
509 (void) XFillRectangle(d, /* display */
510 pixmap, /* drawable */
514 width * 16, /* width */
515 (lineDrawFont->numGlyphs + 15) / 16 * (height));
518 /* reset the GC so we can fill in the lines and rectangles... */
519 (void) XSetForeground(d, gc, 1);
520 #endif /* USE_PIXMAPS */
522 _DtTermProcessUnlock();
523 return(lineDrawFont);
527 _DtTermPrimLineDrawFreeFont(LineDrawFont lineDrawFont)
529 _DtTermProcessLock();
531 /* perform a sanity check... */
532 if (lineDrawFont->refCount <= 0) {
533 _DtTermProcessUnlock();
537 /* decrement the reference count... */
538 (void) lineDrawFont->refCount--;
540 /* we will free the storage if this font is used... */
541 _DtTermProcessUnlock();
547 _DtTermPrimLineDrawImageString(Display *display, Drawable d,
548 LineDrawFont lineDrawFont,
549 GC gc, GC clearGC, int x, int y, unsigned char *string, int width)
554 XRectangle rects[20];
556 #endif /* USE_PIXMAPS */
558 _DtTermProcessLock();
559 if (!lineDrawFont || (lineDrawFont->refCount < 0)) {
560 _DtTermProcessUnlock();
565 /* clear the area... */
566 (void) XFillRectangle(display, /* Display */
570 y - lineDrawFont->ascent, /* y */
571 lineDrawFont->width * width, /* width */
572 lineDrawFont->height); /* height */
573 #endif /* USE_PIXMAPS */
575 /* render the characters... */
576 for (; width > 0; width--, string++) {
577 /* look up glyph through the glyph table... */
578 /* check for valid glyph... */
579 glyph = lineDrawFont->glyphIndex[*string];
581 /* if it is invalid, then let's default to space... */
583 glyph = lineDrawFont->glyphIndex[' '];
585 /* if it is still invalid, then let's skip this character... */
587 x += lineDrawFont->width;
592 /* render this character... */
593 (void) XCopyPlane(display, /* Display */
594 lineDrawFont->pixmap, /* src */
597 lineDrawFont->cellX[glyph], /* src x */
598 lineDrawFont->cellY[glyph], /* src y */
599 lineDrawFont->width, /* width */
600 lineDrawFont->height, /* height */
602 y - lineDrawFont->ascent, /* dest y */
605 #else /* USE_PIXMAPS */
606 if (!lineDrawFont->scaledCharInfo[glyph].scaled) {
607 /* first time, scale this character... */
608 (void) ScaleCharacter(&(lineDrawFont->scaledCharInfo[glyph]),
609 &(lineDrawFont->glyphInfo[glyph]), lineDrawFont->width, lineDrawFont->height);
612 if (lineDrawFont->scaledCharInfo[glyph].numSegs > 0) {
613 for (i = 0; i < lineDrawFont->scaledCharInfo[glyph].numSegs; i++) {
614 segs[i].x1 = x + lineDrawFont->scaledCharInfo[glyph].segs[i].x1;
615 segs[i].x2 = x + lineDrawFont->scaledCharInfo[glyph].segs[i].x2;
617 y + lineDrawFont->scaledCharInfo[glyph].segs[i].y1 -
618 lineDrawFont->ascent;
620 y + lineDrawFont->scaledCharInfo[glyph].segs[i].y2 -
621 lineDrawFont->ascent;
623 (void) XDrawSegments(display, /* Display */
627 lineDrawFont->scaledCharInfo[glyph].numSegs);
631 if (lineDrawFont->scaledCharInfo[glyph].numRects > 0) {
632 for (i = 0; i < lineDrawFont->scaledCharInfo[glyph].numRects; i++) {
633 rects[i].x = x + lineDrawFont->scaledCharInfo[glyph].rects[i].x;
635 y + lineDrawFont->scaledCharInfo[glyph].rects[i].y -
636 lineDrawFont->ascent;
638 lineDrawFont->scaledCharInfo[glyph].rects[i].width;
640 lineDrawFont->scaledCharInfo[glyph].rects[i].height;
642 (void) XFillRectangles(display, /* Display */
645 rects, /* rectangles */
646 lineDrawFont->scaledCharInfo[glyph].numRects);
649 #endif /* USE_PIXMAPS */
650 /* slide over one character... */
651 x += lineDrawFont->width;
654 _DtTermProcessUnlock();