/*********************************************************************** Copyright 1991 by Apple Computer, Inc, Cupertino, California All Rights Reserved Permission to use, copy, modify, and distribute this software for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies. APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS, OR IMPLIED, WITH RESPECT TO THIS SOFTWARE, ITS QUALITY, PERFORMANCE, MERCHANABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS SOFTWARE IS PROVIDED "AS IS," AND YOU THE USER ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND PERFORMANCE. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT IN THE SOFTWARE. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. ***********************************************************************/ #include "MacFont.h" #include #include #include "fntfilst.h" #include "bitmap.h" #include "font.h" #include "MacISO.h" #define TOISO(C) (MacToLatin1[C]) /* Convert a character to ISO Latin1 mapping */ #define TOMAC(C) (Latin1ToMac[C]) /* Convert a character to Mac ASCII mapping */ static void FastCharInkMetrics32(pFont, pCI, pInk) FontPtr pFont; CharInfoPtr pCI; xCharInfo *pInk; { int ascent, descent; unsigned int savebits; register int vpos, inkAscent, inkDescent, lb, rb; register unsigned int *p; register unsigned int charbits; pInk->characterWidth = pCI->metrics.characterWidth; pInk->attributes = pCI->metrics.attributes; ascent = pCI->metrics.ascent; descent = pCI->metrics.descent; p = (unsigned int *) pCI->bits; charbits = 0; inkAscent = ascent + 1; for (vpos = ascent; --vpos >= -descent; p++) { if (*p != 0) { if (inkAscent > ascent) /* must be first inked row */ inkAscent = vpos + 1; inkDescent = -vpos; /* descends at least this far */ charbits |= *p; } } if (inkAscent > ascent) { /* * special case -- font with no bits gets all zeros */ pInk->leftSideBearing = pCI->metrics.leftSideBearing; pInk->rightSideBearing = pCI->metrics.leftSideBearing; pInk->ascent = 0; pInk->descent = 0; return; } else { pInk->ascent = inkAscent; pInk->descent = inkDescent; } savebits = charbits; lb = pCI->metrics.leftSideBearing; while ((charbits & 0x80000000) == 0) { charbits <<= 1; lb++; } pInk->leftSideBearing = lb; charbits = savebits; rb = pCI->metrics.rightSideBearing; while ((charbits & 0x00000001) == 0) { charbits >>= 1; rb--; } pInk->rightSideBearing = rb; } static void FastCharInkMetrics64(pFont, pCI, pInk) FontPtr pFont; CharInfoPtr pCI; xCharInfo *pInk; { int ascent, descent; unsigned int savebits1, savebits2; register int vpos, inkAscent, inkDescent, lb, rb; register unsigned int *p0, *p1; register unsigned int charbits1, charbits2; pInk->characterWidth = pCI->metrics.characterWidth; pInk->attributes = pCI->metrics.attributes; ascent = pCI->metrics.ascent; descent = pCI->metrics.descent; p0 = (unsigned int *) pCI->bits; p1 = p0 + 1; charbits1 = 0; charbits2 = 0; inkAscent = ascent + 1; for (vpos = ascent; --vpos >= -descent; p0 += 2, p1 += 2) { if (*p0 != 0 || *p1 != 0) { if (inkAscent > ascent) /* must be first inked row */ inkAscent = vpos + 1; inkDescent = -vpos; /* descends at least this far */ charbits1 |= *p0; charbits2 |= *p1; } } if (inkAscent > ascent) { /* * special case -- font with no bits gets all zeros */ pInk->leftSideBearing = pCI->metrics.leftSideBearing; pInk->rightSideBearing = pCI->metrics.leftSideBearing; pInk->ascent = 0; pInk->descent = 0; return; } else { pInk->ascent = inkAscent; pInk->descent = inkDescent; } savebits1 = charbits1; savebits2 = charbits2; lb = pCI->metrics.leftSideBearing; if (charbits1) while ((charbits1 & 0x80000000) == 0) { charbits1 <<= 1; lb++; } else { lb += 32; while ((charbits2 & 0x80000000) == 0) { charbits2 <<= 1; lb++; } } pInk->leftSideBearing = lb; charbits1 = savebits1; charbits2 = savebits2; rb = pCI->metrics.rightSideBearing; if(charbits2) while ((charbits2 & 0x00000001) == 0) { charbits2 >>= 1; rb--; } else { rb -= 32; while ((charbits1 & 0x00000001) == 0) { charbits1 >>= 1; rb--; } } pInk->rightSideBearing = rb; } static unsigned char macFirst, macLast; static int widthOf (ch) int ch; { if (ch < macFirst || ch > macLast) { return (0); } else { return (CharWidth (ch)); } } static Point square = {1, 1}; int OpenMacFont (pFont, pMacPriv, name, pixel, res_x, res_y) FontPtr pFont; MacBitmapFontRecPtr pMacPriv; char *name; { char fname [MAXFONTNAMELEN]; char *ptr, *ptr1, *ptr2, *ptr3, *ptr4, *ptr5, *ptr6, *ptr7, *ptr8, *ptr9, *ptr10, *ptr11, *ptr12, *ptr13; char *family_name, *weight_name, *slant, *setwidth_name, *add_style_name, *spacing, *registry, *encoding; GrafPtr pgp, savePort; FMetricRec *pfm; short fNum = 0; short face = normal; pMacPriv->pgp = 0; pMacPriv->pfm = 0; pMacPriv->forceMono = false; pMacPriv->privateEncoding = false; strcpy (fname, name); /* The ptr? below are set at the '-' just preceding the field named in the comment */ if (!(*fname == '-') || /* foundry */ !(ptr1 = ptr = strchr(fname + 1, '-')) || /* family_name */ !(ptr2 = ptr = strchr(ptr + 1, '-')) || /* weight_name */ !(ptr3 = ptr = strchr(ptr + 1, '-')) || /* slant */ !(ptr4 = ptr = strchr(ptr + 1, '-')) || /* setwidth_name */ !(ptr5 = ptr = strchr(ptr + 1, '-')) || /* add_style_name */ !(ptr6 = ptr = strchr(ptr + 1, '-')) || /* pixel_size */ !(ptr7 = ptr = strchr(ptr + 1, '-')) || /* point_size */ !(ptr8 = ptr = strchr(ptr + 1, '-')) || /* resolution_x */ !(ptr9 = ptr = strchr(ptr + 1, '-')) || /* resolution_y */ !(ptr10 = ptr = strchr(ptr + 1, '-')) || /* spacing */ !(ptr11 = ptr = strchr(ptr + 1, '-')) || /* average_width */ !(ptr12 = ptr = strchr(ptr + 1, '-')) || /* charset_registry */ !(ptr13 = ptr = strchr(ptr + 1, '-')) || /* charset_encoding */ strchr(ptr + 1, '-')) /* Too many '-'s ! */ return BadFontName; family_name = ptr1 + 1; *ptr2 = '\0'; weight_name = ptr2 + 1; *ptr3 = '\0'; slant = ptr3 + 1; *ptr4 = '\0'; setwidth_name = ptr4 + 1; *ptr5 = '\0'; add_style_name = ptr5 + 1; *ptr6 = '\0'; spacing = ptr10 + 1; *ptr11 = '\0'; registry = ptr12 + 1; *ptr13 = '\0'; encoding = ptr13 + 1; /* zero terminated at the end of name */ if (!strcmp(weight_name, "bold")) face |= bold; if (!strcmp(slant, "i")) face |= italic; if (!strcmp(setwidth_name, "condensed")) face |= condense; if (!strcmp(setwidth_name, "extended")) face |= extend; if (!strcmp(add_style_name, "underline")) face |= underline; if (!strcmp(add_style_name, "outline")) face |= outline; if (!strcmp(add_style_name, "shadow")) face |= shadow; if (!strcmp(spacing, "m")) pMacPriv->forceMono = true; /* XXX Do we really want to offer this? */ if (!strcmp(registry, "apple") && !strcmp(encoding, "fontspecific")) pMacPriv->privateEncoding = true; pgp = (GrafPtr) NewPtr(sizeof(GrafPort)); if (!pgp) { return (AllocError); } pfm = (FMetricRec *) NewPtr(sizeof(FMetricRec)); if (!pfm) { DisposPtr (pgp); return (AllocError); } GetPort (&savePort); OpenPort (pgp); getfnum (family_name, &fNum); if (!fNum) { char sysName [256]; /* Per technote about font names */ getfontname (systemFont, sysName); if (relstring (sysName, family_name, false, true)) { DisposPtr (pfm); ClosePort (pgp); DisposPtr (pgp); SetPort (savePort); return (BadFontName); } } TextFont (fNum); TextSize (pixel); TextFace (face); FontMetrics (pfm); /* IM Volume 6 12-15 says: Be careful with outline fonts. The font's designer may decide that there is a lower limit to the point size at which the font looks acceptable. */ if (CIsOutline(square, square) && !RealFont(fNum, pixel)) { DisposPtr (pfm); ClosePort (pgp); DisposPtr (pgp); SetPort (savePort); return (BadFontName); } pMacPriv->pgp = pgp; pMacPriv->pfm = pfm; SetPort (savePort); return (Successful); /* Eureka! */ } int ConvertMacFont (pFont, pMacPriv, bit, byte, glyph, scan) FontPtr pFont; MacBitmapFontRecPtr pMacPriv; int bit, byte, glyph, scan; { BitmapFontPtr bitmapFont = (BitmapFontPtr) pFont->fontPrivate; register FontInfoPtr fi; /* Font description */ register CharInfoPtr cip; /* Character being worked on */ register CharInfoPtr *enc; register unsigned ch; int nchars, height; unsigned isoFirst, isoLast; int digitCount, digitWidths; Handle frH; /* FontRec handle -- n.b.: might be sfnt rec handle */ Point numer, denom; GrafPtr savePort; WidthTable *wtP; int maxWidth; short yMin, yMax; BitMap bm, gbm; /* bm is bitmap for gp, gbm is bitmap for pGlyphs */ CharInfoRec bmcip; xCharInfo bmink; Rect srcR, dstR; int bmorg, Mwidth; int gbmSize; OSErr ret; pMacPriv->avgWidth = 0; /* DECIpoints */ pMacPriv->xHeight = 0; pMacPriv->quadWidth = 0; pMacPriv->weight = 0; GetPort (&savePort); SetPort (pMacPriv->pgp); SetCursor (*GetCursor (watchCursor)); wtP = *(WidthTable **) pMacPriv->pfm->wTabHandle; frH = wtP -> tabFont; numer = wtP -> inNumer; denom = wtP -> inDenom; maxWidth = FixRound (pMacPriv->pfm->widMax) * 2; /* Glyphs can be no wider than this */ if (maxWidth < 32) maxWidth = 32; else if (maxWidth < 64) maxWidth = 64; bmorg = maxWidth / 3; /* Start glyphs 1/3 into glyph bitmap */ /* Get first and last used character code values -- form of font record is different if this is an outline (spline) font than if it's a bitmap font Must be done HERE before any alloc */ if (CIsOutline (numer, denom)) { /* Is an outline font, which is terra incognita */ macFirst = 0; macLast = 255; } else { /* Normal bitmap font */ macFirst = (*(MacFontRec **) frH) -> firstChar; macLast = (*(MacFontRec **) frH) -> lastChar; } /* Find the minimum and maximum ISO characters in this font */ if (pMacPriv->privateEncoding) { isoFirst = macFirst; isoLast = macLast; } else for (isoFirst = 255, isoLast = 0, ch = macFirst; ch <= macLast; ++ch) if (widthOf (ch) > 0) { unsigned isoCH = TOISO (ch); if (isoCH < isoFirst) isoFirst = isoCH; if (isoCH > isoLast) isoLast = isoCH; } nchars = isoLast - isoFirst + 1; bitmapFont -> num_chars = nchars; fi = &(pFont -> info); bitmapFont -> metrics = (CharInfoPtr) xalloc (sizeof (CharInfoRec) * nchars); if (!bitmapFont -> metrics) goto memOops; for (cip = bitmapFont -> metrics, ch = isoFirst; ch <= isoLast; ++cip, ++ch) cip -> bits = 0; /* Helps at memOops */ bitmapFont -> encoding = (CharInfoPtr *) xalloc (sizeof (CharInfoPtr *) * nchars); if (!bitmapFont -> encoding) goto memOops; fi -> firstRow = 0; fi -> lastRow = 0; fi -> firstCol = isoFirst; fi -> lastCol = isoLast; fi -> fontAscent = FixRound (pMacPriv->pfm->ascent); fi -> fontDescent = FixRound (pMacPriv->pfm->descent); fi -> allExist = TRUE; if (pMacPriv->privateEncoding) fi -> defaultCh = macFirst; /* A likely candidate, but who really knows ... */ else if (isoFirst < 32) fi -> defaultCh = isoFirst; /* Non-printing, renders as the empty box */ else if (isoLast >= 128) fi -> defaultCh = 128; /* Non-printing, renders as the empty box */ else fi -> defaultCh = isoFirst; /* IM Volume 6, 12-7 says: For bitmapped fonts, the ascent line marks the maximum y-value and the descent line marks the minimum y-value. For outline fonts, a font designer can create individual glyphs that extend above the ascent line or below the descent line. */ if (CIsOutline(numer, denom)) { unsigned char isoChars[256], *p; for (p = isoChars, ch = isoFirst; ch <= isoLast; ++p, ++ch) *p = pMacPriv->privateEncoding ? ch : TOMAC (ch); if ((ret = COutlineMetrics(nchars, isoChars, numer, denom, &yMax, &yMin, NULL, NULL, NULL))) { /* Shouldn't happen, do something rational */ yMin = fi -> fontDescent; yMax = fi -> fontAscent; } else { yMin = -yMin; /* School of hard knocks... */ } } else { yMin = fi -> fontDescent; yMax = fi -> fontAscent; } height = yMax + yMin; digitCount = digitWidths = 0; bm.bounds.left = bm.bounds.top = 0; bm.bounds.bottom = height; bm.bounds.right = maxWidth; bm.rowBytes = BYTES_PER_ROW(maxWidth, glyph); /* Must be even! see MacRenderFont*/ if (pMacPriv->forceMono) Mwidth = widthOf ('M'); bm.baseAddr = (Ptr) xalloc (bm.rowBytes * height); /* Space for glyphs to be drawn in */ if (!bm.baseAddr) goto memOops; bzero (bm.baseAddr, bm.rowBytes * height); PortSize (bm.bounds.right, bm.bounds.bottom); SetPortBits (&bm); bmcip.metrics.ascent = yMax; bmcip.metrics.descent = yMin; bmcip.metrics.leftSideBearing = -bmorg; bmcip.metrics.rightSideBearing = maxWidth - bmorg; bmcip.metrics.characterWidth = maxWidth; /* for the sake of completeness */ bmcip.metrics.attributes = 0; /* for the sake of completeness */ bmcip.bits = bm.baseAddr; for (cip = bitmapFont -> metrics, enc = bitmapFont -> encoding, ch = isoFirst; ch <= isoLast; ++ch, ++enc, ++cip) { int macCH = pMacPriv->privateEncoding ? ch : TOMAC (ch); /* Take care not to lock up the UI for too long. (This is especially important when querying all fonts with info as we have to render all characters to get the info!) */ if ((ch & 0x3F) == 0) MacCheckUI(); *enc = cip; cip -> metrics.attributes = 0; cip -> metrics.characterWidth = widthOf (macCH); if (cip -> metrics.characterWidth <= 0) { cip -> metrics.ascent = 0; cip -> metrics.descent = 0; cip -> metrics.leftSideBearing = 0; cip -> metrics.rightSideBearing = 0; cip -> metrics.characterWidth = 0; cip -> bits = NULL; fi -> allExist = FALSE; continue; } /* Make sure advance width is constant if forceMono is set */ if (pMacPriv->forceMono) cip -> metrics.characterWidth = Mwidth; EraseRect (&bm.bounds); MoveTo (bmorg, yMax); /* Leave a margin to the left of glyph origin */ DrawChar (macCH); /* Now find tight left and right bearings by examining the bits in the bm bitmap */ if (maxWidth == 32) FastCharInkMetrics32(pFont, &bmcip, &bmink); else if (maxWidth == 64) FastCharInkMetrics64(pFont, &bmcip, &bmink); else FontCharInkMetrics(pFont, &bmcip, &bmink); /* Some characters (e.g. 'space') have no inked bits, but positive characterWidth */ if (bmink.ascent == 0 && bmink.descent == 0 && bmink.leftSideBearing == bmink.rightSideBearing) { cip -> metrics.ascent = 0; cip -> metrics.descent = 0; cip -> metrics.leftSideBearing = 0; cip -> metrics.rightSideBearing = 0; cip -> bits = NULL; continue; } #ifndef notdef if (bmcip.metrics.leftSideBearing == bmink.leftSideBearing || bmcip.metrics.rightSideBearing == bmink.rightSideBearing) printf("Bumped against bmcip! ch: 0x%x\n", macCH); #endif cip -> metrics.ascent = bmink.ascent; cip -> metrics.descent = bmink.descent; cip -> metrics.leftSideBearing = bmink.leftSideBearing; cip -> metrics.rightSideBearing = bmink.rightSideBearing; srcR.left = bmorg + bmink.leftSideBearing; srcR.top = yMax - bmink.ascent; srcR.bottom = yMax + bmink.descent; srcR.right = bmorg + bmink.rightSideBearing; /* Set up glyph bitmap descriptor */ gbm.bounds.left = gbm.bounds.top = 0; gbm.bounds.bottom = cip -> metrics.ascent + cip -> metrics.descent; gbm.bounds.right = cip -> metrics.rightSideBearing - cip -> metrics.leftSideBearing; gbm.rowBytes = BYTES_PER_ROW(gbm.bounds.right, glyph); /* Must be even! see MacRenderFont */ gbmSize = gbm.rowBytes * (gbm.bounds.bottom - gbm.bounds.top); gbm.baseAddr = (Ptr) xalloc(gbmSize); if (!gbm.baseAddr) goto memOops; bzero(gbm.baseAddr, gbmSize); cip -> bits = gbm.baseAddr; /* Set up destination so that top edge of glyph is butted against the top of */ /* the font glyph bitmap. */ dstR.left = dstR.top = 0; dstR.bottom = srcR.bottom - srcR.top; dstR.right = srcR.right - srcR.left; /* Copy glyph */ CopyBits (&bm, &gbm, &srcR, &dstR, srcCopy, (RgnHandle) nil); if (bit == LSBFirst) BitOrderInvert(gbm.baseAddr, gbmSize); if (bit != byte) { if (scan == 2) TwoByteSwap(gbm.baseAddr, gbmSize); else if (scan == 4) FourByteSwap(gbm.baseAddr, gbmSize); } pMacPriv->avgWidth += gbm.bounds.right; if (ch == 'x') pMacPriv->xHeight = bmink.ascent; if (ch >= '0' && ch <= '9') { ++digitCount; digitWidths += gbm.bounds.right; } } pMacPriv->avgWidth = (nchars ? (pMacPriv->avgWidth * 10)/nchars : 0); pMacPriv->quadWidth = (digitCount ? (int)((float) digitWidths / (float) digitCount) : 0); xfree (bm.baseAddr); SetPort (savePort); InitCursor (); return (Successful); memOops: if (bitmapFont -> metrics) { for (cip = bitmapFont -> metrics, ch = isoFirst; ch <= isoLast; ++ch, ++cip) { if (cip -> bits) xfree(cip -> bits); } xfree(bitmapFont -> metrics); } if (bitmapFont -> encoding) xfree(bitmapFont -> encoding); if (bm.baseAddr) xfree(bm.baseAddr); if (gbm.baseAddr) xfree(gbm.baseAddr); return (AllocError); }