/************************************************************************ Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ************************************************************************/ /* $Header: fonts.c,v 1.36 87/06/22 21:02:24 toddb Exp $ */ #define NEED←REPLIES #include "X.h" #include "Xmd.h" #include "Xproto.h" #include "dixfontstr.h" #include "fontstruct.h" #include "scrnintstr.h" #include "resource.h" #include "osstruct.h" #include "dix.h" #include "cursorstr.h" #include "misc.h" #include "opaque.h" #include <strings.h> extern FID FiOpenForRead(); static FontPtr pFontHead = NullFont; /* * adding RT←FONT prevents conflict with default cursor font */ SetDefaultFont( defaultfontname) char * defaultfontname; { FontPtr pf; extern FontPtr defaultFont; if ((pf =OpenFont( strlen( defaultfontname), defaultfontname)) == NullFont) return FALSE; AddResource( FakeClientID(0), RT←FONT, (pointer)pf, CloseFont, RC←CORE); defaultFont = pf; return TRUE; } /* * Check reference count first, load font only if necessary. */ FontPtr OpenFont( lenfname, pfilename) int lenfname; char * pfilename; { FontPtr pfont; int lenpname; char * ppathname; FID pf; int nscr; ScreenPtr pscr; FontPtr ReadNFont(); /* * call os-dependent code */ if ( (lenpname = ExpandFontName( &ppathname, lenfname, pfilename)) == 0) { ErrorF( "OpenFont: ExpandFontName failed to find file '%s', (len = %d)\n", pfilename, lenfname); return NullFont; } /* * first look up font name in list of opened fonts */ for ( pfont = pFontHead; pfont != NullFont; pfont = pfont->next) if ( lenpname == pfont->lenpname && strncmp( pfont->pathname, ppathname, pfont->lenpname) == 0) { /* * found it! */ pfont->refcnt += 1; /* Xfree(ppathname); */ return pfont; } /* * if not found in fonts list, read it off disk */ if ( (pf = FiOpenForRead( lenpname, ppathname)) == NullFID) { ErrorF( "OpenFont: failed to open font file %s\n", ppathname); Xfree(ppathname); return NullFont; } pfont = ReadNFont( pf); FiClose( pf); if ( pfont == NullFont) { ErrorF( "OpenFont: ReadNFont failed on file %s\n", ppathname); Xfree(ppathname); return NullFont; } pfont->lenpname = lenpname; pfont->pathname = (char *)Xalloc( lenpname); /* record pathname */ strncpy( pfont->pathname, ppathname, lenpname); pfont->refcnt = 1; pfont->next = pFontHead; /* prepend to fonts list */ pFontHead = pfont; /* * since this font has been newly read off disk, ask each screen to * realize it. */ for ( nscr=0, pscr=screenInfo.screen; nscr<screenInfo.numScreens; nscr++, pscr++) { if ( pscr->RealizeFont) ( *pscr->RealizeFont)( pscr, pfont); } /* Xfree(ppathname); */ return pfont; } /* * Decrement font's ref count, and free storage if ref count equals zero */ int CloseFont( pfont, id) FontPtr pfont; long id; { FontPtr ptf; FontPtr pbtf = NullFont; int nscr; ScreenPtr pscr; for ( ptf = pFontHead; ptf != NullFont; ptf = ptf->next) { if ( ptf == pfont || ptf == NullFont) break; pbtf = ptf; } if ( ptf == NullFont) { ErrorF( "CloseFont: couldn't find font to be closed %x\n", ptf); return; } if ( --ptf->refcnt == 0) { if ( pbtf == NullFont) /* unlink ptf */ pFontHead = ptf->next; else pbtf->next = ptf->next; /* * since the last reference is gone, ask each screen to * free any storage it may have allocated locally for it. */ for ( nscr=0, pscr=screenInfo.screen; nscr<screenInfo.numScreens; nscr++, pscr++) { if ( pscr->UnrealizeFont) ( *pscr->UnrealizeFont)( pscr, ptf); } Xfree( ptf->pathname); Xfree( ptf); if (pfont == defaultFont) defaultFont = NULL; } } /* * description * * Allocates storage with Xalloc(), and returns a pointer to it. * Client can call Xfree() to deallocate font. * * file I/O is all in this routine */ FontPtr ReadNFont( fp) FID fp; /* caller has to FiOpenForRead the file himself */ { FontPtr pfont; FontInfoRec fi; DIXFontProp *pdfp; FontPropPtr pffp; char *propspace; int bytesread, bytestoread, bytestoalloc; int bytesdata; int i; char *strings; /* swap bytes? XXX */ bytestoread = BYTESOFFONTINFO(&fi); if ( (bytesread = FiRead( (char *)&fi, 1, bytestoread, fp)) != bytestoread) { ErrorF("ReadNFont: unexpected EOF\n"); return NullFont; } if (fi.version1 != FONT←FILE←VERSION || fi.version2 != FONT←FILE←VERSION) { ErrorF("ReadNFont: bad font version; expected %d, got %d and %d\n", FONT←FILE←VERSION, fi.version1, fi.version2); return NullFont; } bytesdata = BYTESOFFONTINFO(&fi); bytesdata += BYTESOFCHARINFO(&fi); bytesdata += BYTESOFGLYPHINFO(&fi); bytestoalloc = BYTESOFFONTINFO(&fi)+bytesdata+BYTESOFPROPINFO(&fi); pfont = (FontPtr ) Xalloc(bytestoalloc); bytestoread = bytesdata - BYTESOFFONTINFO(&fi); if ( (bytesread = FiRead( (char *)(&pfont[1]) + BYTESOFFONTINFO(&fi), 1, bytestoread, fp )) != bytestoread) { ErrorF("ReadNFont: unexpected EOF\n"); Xfree(pfont); return NullFont; } /* * now fix up pointers */ pfont->pFI = (FontInfoPtr)&pfont[1]; *pfont->pFI = fi; /* copy date previously read */ pfont->pCI = ADDRCharInfoRec(pfont->pFI); pfont->pGlyphs = ADDRCHARGLYPHS(pfont->pFI); pfont->pFP = ADDRXFONTPROPS(pfont->pFI); /* now read and atom'ize properties */ bytestoalloc = BYTESOFPROPINFO(pfont->pFI) + BYTESOFSTRINGINFO(pfont->pFI); propspace = (char *) Xalloc(bytestoalloc); pffp = (FontPropPtr)propspace; strings = propspace + BYTESOFPROPINFO(pfont->pFI); bytestoread = bytestoalloc; if ( (bytesread = FiRead( (char *)pffp, 1, bytestoread, fp)) != bytestoread) { ErrorF("ReadNFont: unexpected EOF\n"); Xfree(pfont); Xfree(propspace); return NullFont; } for (i=0, pdfp=pfont->pFP; i<fi.nProps; i++, pdfp++, pffp++) { pdfp->name = MakeAtom( &strings[pffp->name], strlen(&strings[pffp->name]), 1); if (pffp->indirect) pdfp->value = (INT32)MakeAtom( &strings[pffp->value], strlen(&strings[pffp->value]), 1); } Xfree(propspace); return pfont; } static void DescribeFont(pfontname, lenfname, pfi, ppfp) char *pfontname; int lenfname; FontInfoPtr pfi; DIXFontProp **ppfp; { FontPtr pfont; FID pf; int i; char *ppathname; int lenpname; int bytesskip, bytesprops; FontInfoRec fi; DIXFontProp *pdfp; FontPropPtr pffp, temp; char *strings; bzero(pfi, sizeof(FontInfoRec)); *ppfp = NullDIXFontProp; /* in case of failure */ if ((lenpname = ExpandFontName(&ppathname, lenfname, pfontname)) == 0) return; /* * first look up font name in list of opened fonts */ for ( pfont = pFontHead; pfont != NullFont; pfont = pfont->next) if ( lenpname == pfont->lenpname && strncmp( pfont->pathname, ppathname, pfont->lenpname) == 0) { *pfi = *pfont->pFI; *ppfp = (DIXFontProp *)Xalloc(sizeof(DIXFontProp)*pfi->nProps); if (*ppfp == NullDIXFontProp) return; bcopy((char *)pfont->pFP, (char *)*ppfp, (int)sizeof(DIXFontProp)*pfi->nProps); return; } /* have to read it off disk */ if ((pf = FiOpenForRead(lenpname, ppathname)) == NullFID) return; if ((FiRead((char *)&fi, 1, sizeof(FontInfoRec), pf) != sizeof(FontInfoRec)) || fi.version1 != FONT←FILE←VERSION || fi.version2 != FONT←FILE←VERSION) return; bytesskip = BYTESOFFONTINFO(&fi) - sizeof(FontInfoRec) + BYTESOFCHARINFO(&fi) + BYTESOFGLYPHINFO(&fi); bytesprops = BYTESOFPROPINFO(&fi) + BYTESOFSTRINGINFO(&fi); temp = (FontPropPtr)Xalloc(max(bytesskip, bytesprops)); if (FiRead((char *)temp, 1, bytesskip, pf) != bytesskip) { Xfree((char *)temp); return; } if (FiRead((char *)temp, 1, bytesprops, pf) != bytesprops) { Xfree((char *)temp); return; } *ppfp = (DIXFontProp *)Xalloc(pfi->nProps * sizeof(DIXFontProp)); if (*ppfp == NullDIXFontProp) { Xfree((char *)temp); return; } strings = (char *)&temp[fi.nProps]; pffp = temp; for (i=0, pdfp=(*ppfp); i<fi.nProps; i++, pdfp++, pffp++) { pdfp->name = MakeAtom( &strings[pffp->name], strlen(&strings[pffp->name]), 1); if (pffp->indirect) pdfp->value = (INT32)MakeAtom( &strings[pffp->value], strlen(&strings[pffp->value]), 1); } Xfree((char *)temp); *pfi = fi; } void DescribeFontList(paths, info) FontPathPtr paths; FontDataPtr info; { int i; for (i=0; i<paths->npaths; i++) { DescribeFont(paths->paths[i], paths->length[i], &info->pFI[i], &info->pFP[i]); } } #ifdef notdef /* * assumes short is 2 bytes and long is 4, but nothing about padding */ #define ←us unsigned short #define ←ul unsigned long #define sw2( p) \ *((←us *)p) = \ *(←us *)p>>8 \ | *(←us *)p<<8; #define sw4( p) \ *((←ul *)p) = \ *(←ul *)p>>24 \ | *(←ul *)p>>8 & 0x0000ff00 \ | *(←ul *)p<<8 & 0x00ff0000 \ | *(←ul *)p<<24; #else #define sw2( p) { \ int t; \ t = ((char *)p)[0]; \ ((char *)p)[0] = ((char *)p)[1]; \ ((char *)p)[1] = t; \ } #define sw4( p) { \ int t; \ t = ((char *)p)[0]; \ ((char *)p)[0] = ((char *)p)[3]; \ ((char *)p)[3] = t; \ t = ((char *)p)[1]; \ ((char *)p)[1] = ((char *)p)[2]; \ ((char *)p)[2] = t; \ } #endif void QueryFont( pf, pr, nprotoxcistructs) FontPtr pf; xQueryFontReply * pr; /* caller must allocate this storage */ int nprotoxcistructs; { FontInfoPtr pfi = pf->pFI; CharInfoPtr pci; DIXFontProp * pfp; int ct; xFontProp * prfp; xCharInfo * prci; void queryCharInfo(); /* pr->length set in dispatch */ pr->minCharOrByte2 = pfi->firstCol; pr->defaultChar = pfi->chDefault; pr->maxCharOrByte2 = pfi->lastCol; pr->drawDirection = pfi->drawDirection; pr->allCharsExist = pfi->allExist; pr->minByte1 = pfi->firstRow; pr->maxByte1 = pfi->lastRow; pr->fontAscent = pfi->fontAscent; pr->fontDescent = pfi->fontDescent; queryCharInfo( &pfi->minbounds, &pr->minBounds); queryCharInfo( &pfi->maxbounds, &pr->maxBounds); pr->nFontProps = pfi->nProps; pr->nCharInfos = nprotoxcistructs; for ( ct=0, pfp=pf->pFP, prfp=(xFontProp *)(&pr[1]); ct < pfi->nProps; ct++, pfp++, prfp++) { prfp->name = pfp->name; prfp->value = pfp->value; } for ( ct=0, pci = &pf->pCI[0], prci=(xCharInfo *)(prfp); ct<nprotoxcistructs; ct++, pci++, prci++) queryCharInfo( pci, prci); } /* static */ void queryCharInfo( pci, pr) CharInfoPtr pci; xCharInfo * pr; /* protocol packet to fill in */ { *pr = pci->metrics; } /* static */ void SwapFont( pr) xQueryFontReply * pr; { int i; xCharInfo * pxci; int nchars, nprops; char *pby; register char n; swapl(&pr->length, n); nchars = pr->nCharInfos; nprops = pr->nFontProps; SwapFontInfo(pr); pby = (char *) &pr[1]; /* Font properties are an atom and either an int32 or a CARD32, so * they are always 2 4 byte values */ for(i = 0; i < nprops; i++) { swapl(pby, n); pby += 4; swapl(pby, n); pby += 4; } pxci = (xCharInfo *)pby; for(i = 0; i< nchars; i++, pxci++) SwapCharInfo(pxci); } SwapFontInfo(pr) xQueryFontReply *pr; { register char n; swaps(&pr->minCharOrByte2, n); swaps(&pr->maxCharOrByte2, n); swaps(&pr->defaultChar, n); swaps(&pr->nFontProps, n); swaps(&pr->fontAscent, n); swaps(&pr->fontDescent, n); SwapCharInfo( &pr->minBounds); SwapCharInfo( &pr->maxBounds); swapl(&pr->nCharInfos, n); } SwapCharInfo(pInfo) xCharInfo *pInfo; { register char n; swaps(&pInfo->leftSideBearing, n); swaps(&pInfo->rightSideBearing, n); swaps(&pInfo->characterWidth, n); swaps(&pInfo->ascent, n); swaps(&pInfo->descent, n); swaps(&pInfo->attributes, n); } /* text support routines. A charinfo array builder, and a bounding */ /* box calculator */ void GetGlyphs(font, count, chars, fontEncoding, glyphcount, glyphs) FontPtr font; int count; register unsigned char *chars; FontEncoding fontEncoding; unsigned int *glyphcount; /* RETURN */ CharInfoPtr glyphs[]; /* RETURN */ { CharInfoPtr pCI = font->pCI; FontInfoPtr pFI = font->pFI; unsigned int firstCol = pFI->firstCol; unsigned int numCols = pFI->lastCol - firstCol + 1; unsigned int firstRow = pFI->firstRow; unsigned int numRows = pFI->lastRow - firstRow + 1; unsigned int chDefault = pFI->chDefault; register int i; int n; register unsigned int c; register CharInfoPtr ci; n = 0; switch (fontEncoding) { case Linear8Bit: case TwoD8Bit: for (i=0; i < count; i++) { c = (*chars++) - firstCol; if (c < numCols) { ci = &pCI[c]; if (ci->exists) {glyphs[n++] = ci; continue;} } c = chDefault - firstCol; if (c < numCols) { ci = &pCI[c]; if (ci->exists) glyphs[n++] = ci; } } break; case Linear16Bit: for (i=0; i < count; i++) { chars++; c = (*chars++) - firstCol; if (c < numCols) { ci = &pCI[c]; if (ci->exists) {glyphs[n++] = ci; continue;} } c = chDefault - firstCol; if (c < numCols) { ci = &pCI[c]; if (ci->exists) glyphs[n++] = ci; } } break; case TwoD16Bit: for (i=0; i < count; i++) { register unsigned int row; register unsigned int col; row = (*chars++) - firstRow; col = (*chars++) - firstCol; if ((row < numRows) && (col < numCols)) { c = row*numCols + col; ci = &pCI[c]; if (ci->exists) {glyphs[n++] = ci; continue;} } row = (chDefault >> 8)-firstRow; col = (chDefault & 0xff)-firstCol; if ((row < numRows) && (col < numCols)) { c = row*numCols + col; ci = &pCI[c]; if (ci->exists) glyphs[n++] = ci; } } break; } *glyphcount = n; } void QueryGlyphExtents(font, charinfo, count, info) FontPtr font; CharInfoPtr *charinfo; unsigned int count; ExtentInfoRec *info; { int i; info->drawDirection = font->pFI->drawDirection; info->fontAscent = font->pFI->fontAscent; info->fontDescent = font->pFI->fontDescent; if (count != 0) { info->overallAscent = charinfo[0]->metrics.ascent; info->overallDescent = charinfo[0]->metrics.descent; info->overallLeft = charinfo[0]->metrics.leftSideBearing; info->overallRight = charinfo[0]->metrics.rightSideBearing; info->overallWidth = charinfo[0]->metrics.characterWidth; for (i=1; i < count; i++) { info->overallAscent = max( info->overallAscent, charinfo[i]->metrics.ascent); info->overallDescent = max( info->overallDescent, charinfo[i]->metrics.descent); info->overallLeft = min( info->overallLeft, info->overallWidth+charinfo[i]->metrics.leftSideBearing); info->overallRight = max( info->overallRight, info->overallWidth+charinfo[i]->metrics.rightSideBearing); /* yes, this order is correct; overallWidth IS incremented last */ info->overallWidth += charinfo[i]->metrics.characterWidth; } } else { info->overallAscent = 0; info->overallDescent = 0; info->overallWidth = 0; info->overallLeft = 0; info->overallRight = 0; } } void QueryTextExtents(font, count, chars, info) FontPtr font; unsigned int count; unsigned short *chars; ExtentInfoRec *info; { CharInfoPtr *charinfo = (CharInfoPtr *)ALLOCATE←LOCAL((int)count*sizeof(CharInfoPtr)); unsigned int n; if(!charinfo) return; if (font->pFI->lastRow == 0) GetGlyphs(font, (int)count, (unsigned char *)chars, Linear16Bit, &n, charinfo); else GetGlyphs(font, (int)count, (unsigned char *)chars, TwoD16Bit, &n, charinfo); QueryGlyphExtents(font, charinfo, n, info); DEALLOCATE←LOCAL(charinfo); }