/* Copyright (c) 1986, 1987 by Hewlett-Packard Company Copyright (c) 1986, 1987 by the Massachusetts Institute of Technology Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. HEWLETT-PACKARD MAKES NO WARRANTY OF ANY KIND WITH REGARD TO THIS SOFWARE, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Hewlett-Packard shall not be liable for errors contained herein or direct, indirect, special, incidental or consequential damages in connection with the furnishing, performance, or use of this material. This software is not subject to any license of the American Telephone and Telegraph Company or of the Regents of the University of California. */ /*********************************************************************** * file: topcatText.c * * * ****************************************************************** * * (c) Copyright Hewlett-Packard Company, 1987. All rights are * * * reserved. Copying or other reproduction of this program * * * except for archival purposes is prohibited without prior * * * written consent of Hewlett-Packard Company. * * ****************************************************************** * * ImageText and PolyText routines for the topcat displays * * Hewlett Packard -- Corvallis Workstation Operation * Project -- port of X11 to HP9000 * Harry Phinney -- MTS * * */ #include <stdio.h> #include <sys/types.h> #include <fcntl.h> #ifndef hpux # include <sys/ioctl.h> # include <grfioctl.h> #else # include <sys/graphics.h> #endif #include "X.h" #include "Xproto.h" #include "../cfb/cfb.h" #include "scrnintstr.h" #include "cursorstr.h" #include "pixmapstr.h" #include "regionstr.h" #include "dixfontstr.h" #include "fontstruct.h" #include "gcstruct.h" #include "windowstr.h" #include "mi.h" #include "topcat.h" #include "hpFonts.h" extern u_char XHP_NewRule[16][6]; /* array of replacement rules */ static void waitAwhile(screenPlanes) unsigned int screenPlanes; { } static void setRegs(hardware, pGC, zmask) TOPCAT *hardware; GCPtr pGC; unsigned int zmask; { if (pGC->bgPixel == -1) { /* * handle special case of PolyText, so PolyText can be fast if * it uses a solid fill */ hardware->write_enable = zmask & pGC->fgPixel; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][4]; hardware->write_enable = zmask & ~pGC->fgPixel; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][5]; } else { /* * Set registers for normal ImageText case. Note that pGC->alu * is ignored, and GXcopy is forced. */ hardware->write_enable = zmask & ~pGC->fgPixel & ~pGC->bgPixel; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [0]; hardware->write_enable = zmask & ~pGC->fgPixel & pGC->bgPixel; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [1]; hardware->write_enable = zmask & pGC->fgPixel & ~pGC->bgPixel; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [2]; hardware->write_enable = zmask & pGC->fgPixel & pGC->bgPixel; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [3]; } hardware->frame_buf_write_enable = zmask; hardware->write_enable = zmask; hardware->pixel_write_replacement_rule = GXcopy; } /************************************************************************ * Routine: tcImageOptText * Render text strings to the display with "optimized" fonts. * Uses the Topcat block mover to place the character if the * character has been "optimized" (stored in offscreen memory). * If it's not in offscreen then we call pGC->ImageGlyphBlt. * It is assumed that these are *terminal fonts*, drawn left * to right, and have the most-used characters stored in * offscreen memory. The characters must be stored in increasing * order in the chunks, e.g. char 78 *must* be further down the * list of chunks than char 57, though char 63 doesn't have to * be stored in offscreen. No chunk can have holes - the chars * must be contiguous within a chunk. In the example above, if * char 63 isn't stored, 57 and 78 *must* be in different chunks. * * If pGC->bgPixel is -1, then assume we are being called by * PolyText, and make the glyph background a no-op (transparent). * This allows PolyText to be fast iff FillStyle == Solid. * * Inputs: pDraw points to the drawable we're to print to * pGC points to the GC we're to use * x, y is the starting location for the string in the drawable * count is the number of characters we're to put out * chars points to an array of the characters we're to put out(!) * encoding is Linear8Bit, Linear16Bit, etc. * * Returns: nothing * * Side Effects: none * */ void tcImageOptTEText8(pDraw, pGC, dstx, dsty, count, chars /*, encoding */) DrawablePtr pDraw; GCPtr pGC; int dstx, dsty; int count; u_char *chars; /* FontEncoding encoding; */ { #if 0 FontEncoding encoding = Linear8Bit; /* should be passed in ... */ register TOPCAT *hardware = getTcHardware(pDraw->pScreen); unsigned long screenPlanes = getPlanesMask(pDraw->pScreen); unsigned long zmask = pGC->planemask & screenPlanes; int fore = pGC->fgPixel; int back = pGC->bgPixel; FontPtr pfont = pGC->font; CharInfoPtr pCI = pfont->pCI; register unsigned int firstCol = FONTFIRSTCOL(pfont); int numCols = FONTLASTCOL(pfont) - firstCol + 1; unsigned int chDefault = FONTDEFAULTCH(pfont); hpFontRec *pfrec = (hpFontRec *)(pfont->devPriv[pDraw->pScreen->myNum]); hpChunk *pChunk; Bool fDefaultExists = pfrec->fDefaultExists; RegionPtr pRegion = ((cfbPrivGC *)pGC->devPrivates[cfbGCPrivateIndex].ptr)->pCompositeClip; register BoxPtr pBox = REGION_RECTS(pRegion); int nbox = REGION_NUM_RECTS(pRegion); int x, y, dx, dy, h, w; int srcx, srcy; int found; /* flag for in/out of offscreen */ /* * some stupid applications send a request to output a zero length * string, so I have to check for it. */ if (!count) return; /* * absolutize the coordinates */ dstx += pDraw->x; dsty += pDraw->y; /* * adjust dsty from char baseline to top edge * because we assume terminal fonts, all ascents are the same */ dsty -= FONTMAXBOUNDS(pfont,ascent); while (screenPlanes & hardware->move_active) waitAwhile(screenPlanes); setRegs(hardware, pGC, zmask); switch (encoding) { case Linear8Bit: case TwoD8Bit: for (; nbox--; pBox++) { /* for each clip box */ /* * because we assume terminal fonts, we just need the w & h * of any random character from the font * (since they're all the same) */ w = pfrec->maxWidth; h = pfrec->maxHeight; y = dsty; dx = 0; dy = 0; /* * clip the height only once since all chars are same height&ascent */ if (y < pBox->y1) { dy = pBox->y1 - y; h -= dy; y = pBox->y1; } if (y+h > pBox->y2) h -= y + h - pBox->y2; /* * if any part is in the y-band of the box, write it */ if (h > 0) { register u_char *str = chars; register unsigned char st; register slen = count; x = dstx; if (x < pBox->x1) { /* * while the character is to the left of the clipping * rectangle, go to the next character */ while (x+w <= pBox->x1) { if (--slen == 0) break; x += w; str++; } if (!slen) continue; /* * clip the first "in" character to the edge */ if ((dx = pBox->x1 - x) < 0) dx = 0; if (x+dx >= pBox->x2) continue; } /* * trim length to right edge of pBox */ if ((x + w*slen) >= pBox->x2) { /* compute ceiling((pBox->x2 - x)/w) */ slen = min((pBox->x2 - x + w - 1)/w, slen); if (slen <= 0) continue; } /* * if the first glyph is clipped by the left edge, * put it out */ if (dx) { st = *str++; slen--; while (!fDefaultExists && ((st < firstCol) || (st > FONTLASTCOL(pfont)) || !pCI[st - firstCol].exists)) { /* * if the default char doesn't exist, and this character * doesn't exist, then go on to next character */ if (!--slen) continue; st = *str++; } found = 0; /* * find the char's location in offscreen (hopefully) */ if (st >= pfrec->firstChar && st <= pfrec->lastChar) { srcx = (pChunk = pfrec->ppChunk[(st - pfrec->firstChar) >> 5])->x + ((st - pfrec->firstChar) % 32) * pfrec->maxWidth; srcy = pChunk->y; found = 1; } if (!found) { CharInfoPtr pci; int oldTranslate = pGC->miTranslate; pGC->miTranslate = 0; /* we already translated it */ if ((st < firstCol) || (st > FONTLASTCOL(pfont)) || !(pci = &pCI[st - firstCol])->exists) { /* * we know the default char exists, or we * would have skipped over this glyph. * So put out the default glyph */ pci = &pCI[chDefault - firstCol]; } if (back == -1) { (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, dsty + FONTMAXBOUNDS(pfont,ascent), 1, &pci, FONTGLYPHS(pfont)); hardware->write_enable = zmask & fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][4]; hardware->write_enable = zmask & ~fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][5]; } else { (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, dsty + FONTMAXBOUNDS(pfont,ascent), 1, &pci, FONTGLYPHS(pfont)); hardware->write_enable = zmask & ~fore & ~back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [0]; hardware->write_enable = zmask & ~fore & back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [1]; hardware->write_enable = zmask & fore & ~back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [2]; hardware->write_enable = zmask & fore & back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [3]; } pGC->miTranslate = oldTranslate; hardware->write_enable = zmask; hardware->frame_buf_write_enable = zmask; hardware->pixel_write_replacement_rule = GXcopy; } else { /* * use the block mover to place the glyph */ if (!slen) { if (x+w > pBox->x2) { /* clip last char to right edge */ w = pBox->x2 - x; } } while (screenPlanes & hardware->move_active) waitAwhile(screenPlanes); hardware->source_x = srcx + dx; hardware->source_y = srcy + dy; hardware->dest_x = x + dx; hardware->dest_y = y; hardware->window_width = w - dx; hardware->window_height = h; hardware->start_move = zmask; } x += w; /* move to start pos of next char on screen */ if (!slen) continue; } /* * completely inside the clip box, put out each character */ for (st = *str++; slen--; st = *str++) { if (!fDefaultExists && ((st < firstCol) || (st > numCols) || !pCI[st - firstCol].exists)) { /* * if the default char doesn't exist, and this * character doesn't exist, then do nothing */ continue; } found = 0; if (st >= pfrec->firstChar && st <= pfrec->lastChar) { srcx = (pChunk = pfrec->ppChunk[(st - pfrec->firstChar) >> 5])->x + ((st - pfrec->firstChar) % 32) * pfrec->maxWidth; srcy = pChunk->y; found = 1; } if (!found) { /* * the char wasn't in any chunk, so call ImageGlyphBlt */ CharInfoPtr pci; int oldTranslate = pGC->miTranslate; pGC->miTranslate = 0; /* we already translated it */ if ((st < firstCol) || (st > numCols) || !(pci = &pCI[st - firstCol])->exists) { /* * we know the default char exists, or we * would have skipped over this glyph. * So put out the default glyph */ pci = &pCI[chDefault - firstCol]; } if (back == -1) { (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, dsty + FONTMAXBOUNDS(pfont,ascent), 1, &pci, FONTGLYPHS(pfont)); hardware->write_enable = zmask & fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][4]; hardware->write_enable = zmask & ~fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][5]; } else { (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, dsty + FONTMAXBOUNDS(pfont,ascent), 1, &pci, FONTGLYPHS(pfont)); hardware->write_enable = zmask & ~fore & ~back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [0]; hardware->write_enable = zmask & ~fore & back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [1]; hardware->write_enable = zmask & fore & ~back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [2]; hardware->write_enable = zmask & fore & back; hardware->window_move_replacement_rule = XHP_NewRule[GXcopy] [3]; } pGC->miTranslate = oldTranslate; hardware->write_enable = zmask; hardware->frame_buf_write_enable = zmask; hardware->pixel_write_replacement_rule = GXcopy; } else { /* * use the block mover to place the glyph */ if (!slen) { if (x+w > pBox->x2) { /* clip last char to right edge */ w = pBox->x2 - x; } } while(screenPlanes & hardware->move_active) waitAwhile(screenPlanes); hardware->source_x = srcx; hardware->source_y = srcy + dy; hardware->dest_x = x; hardware->dest_y = y; hardware->window_width = w; hardware->window_height = h; hardware->start_move = zmask; } x += w; /* move to start pos of next char on screen */ } } } break; case Linear16Bit: case TwoD16Bit: break; } #endif } /************************************************************************ * Routine: tcImageVarText * Render text strings to the display with "optimized" fonts * in the case where the font is variable-width, and varible * ascent, etc. * Uses the Topcat block mover to place the character if the * character has been "optimized" (stored in offscreen memory). * If it's not in offscreen then we call pGC->ImageGlyphBlt. * It is assumed that these characters are drawn left * to right, and have the most-used characters stored in * offscreen memory. The characters must be stored in increasing * order in the chunks, e.g. char 78 *must* be further down the * list of chunks than char 57, though char 63 doesn't have to * be stored in offscreen. No chunk can have holes - the chars * must be contiguous within a chunk. In the example above, if * char 63 isn't stored, 57 and 78 *must* be in different chunks. * * If pGC->bgPixel is -1, then assume we are being called by * PolyText, and make the glyph background a no-op (transparent). * This allows PolyText to be fast iff FillStyle == Solid. * * Inputs: pDraw points to the drawable we're to print to * pGC points to the GC we're to use * x, y is the starting location for the string in the drawable * count is the number of characters we're to put out * chars points to an array of the characters we're to put out * encoding is Linear8Bit, Linear16Bit, etc. * * Returns: nothing * * Side Effects: none * */ void tcImageOptText8(pDraw, pGC, dstx, dsty, count, chars /*, encoding */) DrawablePtr pDraw; GCPtr pGC; int dstx, dsty; int count; u_char *chars; /* FontEncoding encoding; */ { #if 0 FontEncoding encoding = Linear8Bit; /* should be passed in ... */ register TOPCAT *hardware = getTcHardware(pDraw->pScreen); int XHP_bits = hardware->bits; unsigned long screenPlanes = getPlanesMask(pDraw->pScreen); unsigned long zmask = pGC->planemask & screenPlanes; int fore = pGC->fgPixel; int back = pGC->bgPixel; FontPtr pfont = pGC->font; unsigned int firstCol = FONTFIRSTCOL(pfont); unsigned int numCols = FONTLASTCOL(pfont) - firstCol + 1; unsigned int chDefault = FONTDEFAULTCH(pfont); int miny, maxy, minx, maxx; CharInfoPtr pCI = pfont->pCI; CharInfoPtr *ppCI; ExtentInfoRec info; hpFontRec *pfrec = (hpFontRec *)(pfont->devPriv[pDraw->pScreen->myNum]); hpChunk *pChunk; int numChunks = pfrec->NumChunks; hpCharRange *pRange; unsigned int maxWidth = pfrec->maxWidth; RegionPtr pRegion = ((cfbPrivGC *)pGC->devPrivates[cfbGCPrivateIndex].ptr)->pCompositeClip; register BoxPtr pBox = REGION_RECTS(pRegion); int nbox = REGION_NUM_RECTS(pRegion); register int i, x, y, dx, dy, h, w, oldAlu, oldFS; int n; CARD32 oldFG; int srcx, srcy; int found = 0; /* flag for in/out of offscreen */ if (!count) return; if (back != -1) { /* * Fill the background rectangle to the background color */ /* * build the array of CharInfo struct pointers for glyphs in the string */ if (!(ppCI = (CharInfoPtr *)ALLOCATE_LOCAL(count*sizeof(CharInfoPtr)))) return; GetGlyphs(pfont, count, chars, Linear8Bit, &n, ppCI); QueryGlyphExtents(pGC->font, ppCI, n, &info); oldAlu = pGC->alu; oldFG = pGC->fgPixel; oldFS = pGC->fillStyle; /* fill in the background */ pGC->alu = (long) GXcopy; pGC->fgPixel = (long) pGC->bgPixel; pGC->fillStyle = (long) FillSolid; tcPaintBlockClipped(pDraw,pGC, dstx + ((pDraw->type == DRAWABLE_WINDOW) ? pDraw->x : PIXER(pDraw)->pChunk->x), dsty - FONTASCENT(pGC->font) + ((pDraw->type == DRAWABLE_WINDOW) ? pDraw->y : PIXER(pDraw)->pChunk->y), info.overallWidth, FONTASCENT(pGC->font) + FONTDESCENT(pGC->font)); /* * put the GC back except for alu * in an ImageText, the effective alu is GXcopy */ pGC->fgPixel = oldFG; pGC->fillStyle = oldFS; } /* * absolutize the coordinates */ dstx += pDraw->x; dsty += pDraw->y; miny = dsty - FONTMAXBOUNDS(pfont,ascent); maxy = dsty + FONTMAXBOUNDS(pfont,descent); minx = dstx + FONTMINBOUNDS(pfont,leftSideBearing); /* is this right? */ maxx = dstx + count * maxWidth; waitbusy(screenPlanes, hardware); /* * set a PolyText type of replacement rule. * we've cleared the background rectangle for the string in the case * of an Imagetext call. */ hardware->write_enable = zmask & fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][4]; hardware->write_enable = zmask & ~fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][5]; hardware->write_enable = zmask; hardware->frame_buf_write_enable = zmask; hardware->pixel_write_replacement_rule = GXcopy; switch (encoding) { case Linear8Bit: case TwoD8Bit: while (nbox--) { /* for each clip box */ /* * check to see if any characters may be in the clip box * if any part may be in the box, write it */ if ((pBox->x1 <= maxx) && (minx <= pBox->x2) && (pBox->y1 <= maxy) && (miny <= pBox->y2)) { register int slen = count; register u_char *str = chars; register unsigned char st = *str++; CharInfoPtr pci = pCI + st - firstCol; x = dstx; while ((st < firstCol) || (st > numCols) || !pci->exists) { /* * check for non-existent glyphs & replace w/the default * or skip it if the default doesn't exist */ if ((chDefault < firstCol) || !pCI[chDefault - firstCol].exists) { /* * if the default char doesn't exist, then do nothing */ st = *str++; pci = pCI + st - firstCol; if (--slen == 0) break; continue; } pci = pCI + chDefault - firstCol; st = chDefault; } /* * while the character is to the left of the clipping * rectangle, go to the next character */ while ((x+(w = pci->metrics.characterWidth)) <= pBox->x1) { if (--slen <= 0) { if (slen < 0) slen = 0; break; } x += w; st = *str++; pci = pCI + st - firstCol; if (!pci->exists) { pci = pCI + (chDefault - firstCol); st = chDefault; } } /* * clip the first "in" character to the edge */ if ((dx = pBox->x1 - (x+pci->metrics.leftSideBearing)) < 0) dx = 0; if ((x+dx+pci->metrics.leftSideBearing) > pBox->x2) slen = 0; /* * in the clip box, put out each character */ while (slen--) { /* for each char left in the string */ pci = &pCI[st - firstCol]; if ((st < firstCol) || (st > numCols) || !pci->exists) { /* * check for non-existent glyphs & replace w/the default */ st = chDefault; pci = &pCI[chDefault - firstCol]; if (st < firstCol || (st > numCols) || !pci->exists) { /* * if the default doesn't exist, skip the char */ st = *str++; continue; } } /* * find the char's location in offscreen (hopefully) */ found = 0; /* flag for in/out of offscreen */ for (i = 0, pRange = pfrec->pRange; i < numChunks; i++, pRange++) { if (st <= pRange->endChar) { if (st >= pRange->startChar) { found = 1; /* we found it */ pChunk = pfrec->ppChunk[i]; srcx = pChunk->x + maxWidth * (st - pRange->startChar); srcy = pChunk->y; break; } else { /* * it's not in any of the chunks */ break; } } } if (!found) { /* * the char wasn't in any chunk, so call ImageGlyphBlt */ CharInfoPtr localpci = &pCI[st - firstCol]; int oldTranslate = pGC->miTranslate; pGC->miTranslate = 0; /* we already translated it */ if (back == -1) (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, dsty, 1, &localpci, FONTGLYPHS(pfont)); else (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, dsty, 1, &localpci, FONTGLYPHS(pfont)); hardware->write_enable = zmask & fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][4]; hardware->write_enable = zmask & ~fore; hardware->window_move_replacement_rule = XHP_NewRule[pGC->alu][5]; hardware->write_enable = zmask; hardware->frame_buf_write_enable = zmask; hardware->pixel_write_replacement_rule = GXcopy; pGC->miTranslate = oldTranslate; /* put it back */ } else { /* * use the block mover to place the glyph */ w = GLWIDTHPIXELS(pci); if (x+w+pci->metrics.leftSideBearing > pBox->x2) { /* clip to right edge */ w = pBox->x2 - (x + pci->metrics.leftSideBearing); } /* * clip the height of the glyph */ y = dsty - pci->metrics.ascent; dy = 0; h = GLHEIGHTPIXELS(pci); if (y < pBox->y1) { dy = pBox->y1 - y; h -= dy; y = pBox->y1; } if (y+h > pBox->y2) h -= y + h -pBox->y2; if ((h > 0) && (w > dx)) { waitbusy(screenPlanes, hardware); hardware->source_x = (srcx + dx) << XHP_bits; hardware->source_y = srcy + dy; hardware->dest_x = (x + dx + pci->metrics.leftSideBearing) << XHP_bits; hardware->dest_y = y; hardware->window_width = (w - dx) << XHP_bits; hardware->window_height = h; hardware->start_move = zmask; } } /* move to start pos of next char on screen */ x += pci->metrics.characterWidth; dx = 0; if (x >= pBox->x2) slen = 0; /* no more within pBox */ st = *str++; } } pBox++; } break; case Linear16Bit: case TwoD16Bit: break; } if (back != -1) /* put the alu back right */ pGC->alu = oldAlu; DEALLOCATE_LOCAL(ppCI); #endif } int tcPolyOptText8(pDraw, pGC, dstx, dsty, count, chars /*, encoding */) DrawablePtr pDraw; GCPtr pGC; int dstx, dsty; int count; u_char *chars; /* FontEncoding encoding; */ { #if 0 if ((pGC->alu == GXcopy) && (pGC->fillStyle == FillSolid)) { /* * it looks enough like an imagetext that we can use tcImage???Text */ register FontPtr pFont = pGC->font; int oldBackground; CharInfoPtr pci = pFont->pCI; unsigned char *thischar = chars; /* * set background to -1 to tell tcImage???Text that the background * should be transparent (no-op) */ oldBackground = pGC->bgPixel; pGC->bgPixel = -1; (* pGC->ops->ImageText8)(pDraw, pGC, dstx, dsty, count, chars); pGC->bgPixel = oldBackground; while (count--) { dstx += pci[*thischar].metrics.characterWidth; thischar++; } return dstx; } else return miPolyText8(pDraw, pGC, dstx, dsty, count, chars); #endif }