/* $Xorg: bitscale.c,v 1.5 2001/02/09 02:04:02 xorgcvs Exp $ */ /* Copyright 1991, 1994, 1998 The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. */ /* $XFree86: xc/lib/font/bitmap/bitscale.c,v 3.29tsi Exp $ */ /* * Author: Keith Packard, MIT X Consortium */ #ifdef HAVE_CONFIG_H #include <config.h> #endif /* * Translate monolithic #defines to modular definitions */ #ifdef PCFFORMAT #define XFONT_PCFFORMAT 1 #endif #ifdef SNFFORMAT #define XFONT_SNFFORMAT 1 #endif #ifdef BDFFORMAT #define XFONT_BDFFORMAT 1 #endif #include <X11/fonts/fntfilst.h> #include <X11/fonts/bitmap.h> #include <X11/fonts/fontutil.h> #ifndef FONTMODULE #ifdef _XOPEN_SOURCE #include <math.h> #else #define _XOPEN_SOURCE /* to get prototype for hypot on some systems */ #include <math.h> #undef _XOPEN_SOURCE #endif #endif #ifndef MAX #define MAX(a,b) (((a)>(b)) ? a : b) #endif /* Should get this from elsewhere */ extern unsigned long serverGeneration; static void bitmapUnloadScalable (FontPtr pFont); static void ScaleBitmap ( FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci, double *inv_xform, double widthMult, double heightMult ); static FontPtr BitmapScaleBitmaps(FontPtr pf, FontPtr opf, double widthMult, double heightMult, FontScalablePtr vals); static FontPtr PrinterScaleBitmaps(FontPtr pf, FontPtr opf, double widthMult, double heightMult, FontScalablePtr vals); enum scaleType { atom, truncate_atom, pixel_size, point_size, resolution_x, resolution_y, average_width, scaledX, scaledY, unscaled, fontname, raw_ascent, raw_descent, raw_pixelsize, raw_pointsize, raw_average_width, uncomputed }; typedef struct _fontProp { char *name; Atom atom; enum scaleType type; } fontProp; typedef FontPtr (*ScaleFunc) ( FontPtr /* pf */, FontPtr /* opf */, double /* widthMult */, double /* heightMult */, FontScalablePtr /* vals */); /* These next two arrays must be kept in step with the renderer array */ ScaleFunc scale[] = { #if XFONT_PCFFORMAT BitmapScaleBitmaps, BitmapScaleBitmaps, #ifdef X_GZIP_FONT_COMPRESSION BitmapScaleBitmaps, #endif #endif #if XFONT_SNFFORMAT BitmapScaleBitmaps, BitmapScaleBitmaps, #ifdef X_GZIP_FONT_COMPRESSION BitmapScaleBitmaps, #endif #endif #if XFONT_BDFFORMAT BitmapScaleBitmaps, BitmapScaleBitmaps, #ifdef X_GZIP_FONT_COMPRESSION BitmapScaleBitmaps, #endif #endif #if XFONT_PCFFORMAT PrinterScaleBitmaps, #endif }; static FontEntryPtr FindBestToScale ( FontPathElementPtr fpe, FontEntryPtr entry, FontScalablePtr vals, FontScalablePtr best, double *dxp, double *dyp, double *sdxp, double *sdyp, FontPathElementPtr *fpep ); static FontEntryPtr FindPmfToScale ( FontPathElementPtr fpe, FontEntryPtr entry, FontScalablePtr vals, FontScalablePtr best, double *dxp, double *dyp, double *sdxp, double *sdyp, FontPathElementPtr *fpep ); typedef FontEntryPtr (*FindToScale) (FontPathElementPtr fpe, FontEntryPtr entry, FontScalablePtr vals, FontScalablePtr best, double *dxp, double *dyp, double *sdxp, double *sdyp, FontPathElementPtr *fpep); FindToScale find_scale[] = { #if XFONT_PCFFORMAT FindBestToScale, FindBestToScale, #ifdef X_GZIP_FONT_COMPRESSION FindBestToScale, #endif #endif #if XFONT_SNFFORMAT FindBestToScale, FindBestToScale, #ifdef X_GZIP_FONT_COMPRESSION FindBestToScale, #endif #endif #if XFONT_BDFFORMAT FindBestToScale, FindBestToScale, #ifdef X_GZIP_FONT_COMPRESSION FindBestToScale, #endif #endif #if XFONT_PCFFORMAT FindPmfToScale, #endif }; static unsigned long bitscaleGeneration = 0; /* initialization flag */ static fontProp fontNamePropTable[] = { { "FOUNDRY", 0, atom }, { "FAMILY_NAME", 0, atom }, { "WEIGHT_NAME", 0, atom }, { "SLANT", 0, atom }, { "SETWIDTH_NAME", 0, atom }, { "ADD_STYLE_NAME", 0, atom }, { "PIXEL_SIZE", 0, pixel_size }, { "POINT_SIZE", 0, point_size }, { "RESOLUTION_X", 0, resolution_x }, { "RESOLUTION_Y", 0, resolution_y }, { "SPACING", 0, atom }, { "AVERAGE_WIDTH", 0, average_width }, { "CHARSET_REGISTRY", 0, atom }, { "CHARSET_ENCODING", 0, truncate_atom }, { "FONT", 0, fontname }, { "RAW_ASCENT", 0, raw_ascent }, { "RAW_DESCENT", 0, raw_descent }, { "RAW_PIXEL_SIZE", 0, raw_pixelsize }, { "RAW_POINT_SIZE", 0, raw_pointsize }, { "RAW_AVERAGE_WIDTH", 0, raw_average_width } }; #define TRANSFORM_POINT(matrix, x, y, dest) \ ((dest)[0] = (matrix)[0] * (x) + (matrix)[2] * (y), \ (dest)[1] = (matrix)[1] * (x) + (matrix)[3] * (y)) #define CHECK_EXTENT(lsb, rsb, desc, asc, data) \ ((lsb) > (data)[0] ? (lsb) = (data)[0] : 0 , \ (rsb) < (data)[0] ? (rsb) = (data)[0] : 0, \ (-desc) > (data)[1] ? (desc) = -(data)[1] : 0 , \ (asc) < (data)[1] ? (asc) = (data)[1] : 0) #define NPROPS (sizeof(fontNamePropTable) / sizeof(fontProp)) /* Warning: order of the next two tables is critically interdependent. Location of "unscaled" properties at the end of fontPropTable[] is important. */ static fontProp fontPropTable[] = { { "MIN_SPACE", 0, scaledX }, { "NORM_SPACE", 0, scaledX }, { "MAX_SPACE", 0, scaledX }, { "END_SPACE", 0, scaledX }, { "AVG_CAPITAL_WIDTH", 0, scaledX }, { "AVG_LOWERCASE_WIDTH", 0, scaledX }, { "QUAD_WIDTH", 0, scaledX }, { "FIGURE_WIDTH", 0, scaledX }, { "SUPERSCRIPT_X", 0, scaledX }, { "SUPERSCRIPT_Y", 0, scaledY }, { "SUBSCRIPT_X", 0, scaledX }, { "SUBSCRIPT_Y", 0, scaledY }, { "SUPERSCRIPT_SIZE", 0, scaledY }, { "SUBSCRIPT_SIZE", 0, scaledY }, { "SMALL_CAP_SIZE", 0, scaledY }, { "UNDERLINE_POSITION", 0, scaledY }, { "UNDERLINE_THICKNESS", 0, scaledY }, { "STRIKEOUT_ASCENT", 0, scaledY }, { "STRIKEOUT_DESCENT", 0, scaledY }, { "CAP_HEIGHT", 0, scaledY }, { "X_HEIGHT", 0, scaledY }, { "ITALIC_ANGLE", 0, unscaled }, { "RELATIVE_SETWIDTH", 0, unscaled }, { "RELATIVE_WEIGHT", 0, unscaled }, { "WEIGHT", 0, unscaled }, { "DESTINATION", 0, unscaled }, { "PCL_FONT_NAME", 0, unscaled }, { "_ADOBE_POSTSCRIPT_FONTNAME", 0, unscaled } }; /* sleazy way to shut up the compiler */ #define zerohack (enum scaleType)0 static fontProp rawFontPropTable[] = { { "RAW_MIN_SPACE", 0, }, { "RAW_NORM_SPACE", 0, }, { "RAW_MAX_SPACE", 0, }, { "RAW_END_SPACE", 0, }, { "RAW_AVG_CAPITAL_WIDTH", 0, }, { "RAW_AVG_LOWERCASE_WIDTH", 0, }, { "RAW_QUAD_WIDTH", 0, }, { "RAW_FIGURE_WIDTH", 0, }, { "RAW_SUPERSCRIPT_X", 0, }, { "RAW_SUPERSCRIPT_Y", 0, }, { "RAW_SUBSCRIPT_X", 0, }, { "RAW_SUBSCRIPT_Y", 0, }, { "RAW_SUPERSCRIPT_SIZE", 0, }, { "RAW_SUBSCRIPT_SIZE", 0, }, { "RAW_SMALL_CAP_SIZE", 0, }, { "RAW_UNDERLINE_POSITION", 0, }, { "RAW_UNDERLINE_THICKNESS", 0, }, { "RAW_STRIKEOUT_ASCENT", 0, }, { "RAW_STRIKEOUT_DESCENT", 0, }, { "RAW_CAP_HEIGHT", 0, }, { "RAW_X_HEIGHT", 0, } }; static void initFontPropTable(void) { int i; fontProp *t; i = sizeof(fontNamePropTable) / sizeof(fontProp); for (t = fontNamePropTable; i; i--, t++) t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); i = sizeof(fontPropTable) / sizeof(fontProp); for (t = fontPropTable; i; i--, t++) t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); i = sizeof(rawFontPropTable) / sizeof(fontProp); for (t = rawFontPropTable; i; i--, t++) t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); } #if 0 static FontEntryPtr GetScalableEntry (FontPathElementPtr fpe, FontNamePtr name) { FontDirectoryPtr dir; dir = (FontDirectoryPtr) fpe->private; return FontFileFindNameInDir (&dir->scalable, name); } #endif static double get_matrix_horizontal_component(double *matrix) { return hypot(matrix[0], matrix[1]); } static double get_matrix_vertical_component(double *matrix) { return hypot(matrix[2], matrix[3]); } static Bool ComputeScaleFactors(FontScalablePtr from, FontScalablePtr to, double *dx, double *dy, double *sdx, double *sdy, double *rescale_x) { double srcpixelset, destpixelset, srcpixel, destpixel; srcpixelset = get_matrix_horizontal_component(from->pixel_matrix); destpixelset = get_matrix_horizontal_component(to->pixel_matrix); srcpixel = get_matrix_vertical_component(from->pixel_matrix); destpixel = get_matrix_vertical_component(to->pixel_matrix); if (srcpixelset >= EPS) { *dx = destpixelset / srcpixelset; *sdx = 1000.0 / srcpixelset; } else *sdx = *dx = 0; *rescale_x = 1.0; /* If client specified a width, it overrides setsize; in this context, we interpret width as applying to the font before any rotation, even though that's not what is ultimately returned in the width field. */ if (from->width > 0 && to->width > 0 && fabs(*dx) > EPS) { double rescale = (double)to->width / (double)from->width; /* If the client specified a transformation matrix, the rescaling for width does *not* override the setsize. Instead, just check for consistency between the setsize from the matrix and the setsize that would result from rescaling according to the width. This assumes (perhaps naively) that the width is correctly reported in the name. As an interesting side effect, this test may result in choosing a different source bitmap (one that scales consistently between the setsize *and* the width) than it would choose if a width were not specified. Sort of a hidden multiple-master functionality. */ if ((to->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY || (to->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) { /* Reject if resulting width difference is >= 1 pixel */ if (fabs(rescale * from->width - *dx * from->width) >= 10) return FALSE; } else { *rescale_x = rescale/(*dx); *dx = rescale; } } if (srcpixel >= EPS) { *dy = destpixel / srcpixel; *sdy = 1000.0 / srcpixel; } else *sdy = *dy = 0; return TRUE; } /* favor enlargement over reduction because of aliasing resulting from reduction */ #define SCORE(m,s) \ if (m >= 1.0) { \ if (m == 1.0) \ score += (16 * s); \ else if (m == 2.0) \ score += (4 * s); \ else \ score += (int)(((double)(3 * s)) / m); \ } else { \ score += (int)(((double)(2 * s)) * m); \ } /* don't need to favor enlargement when looking for bitmap that can be used unscalable */ #define SCORE2(m,s) \ if (m >= 1.0) \ score += (int)(((double)(8 * s)) / m); \ else \ score += (int)(((double)(8 * s)) * m); static FontEntryPtr FindBestToScale(FontPathElementPtr fpe, FontEntryPtr entry, FontScalablePtr vals, FontScalablePtr best, double *dxp, double *dyp, double *sdxp, double *sdyp, FontPathElementPtr *fpep) { FontScalableRec temp; int source, i; int best_score, best_unscaled_score, score; double dx = 0.0, sdx = 0.0, dx_amount = 0.0, dy = 0.0, sdy = 0.0, dy_amount = 0.0, best_dx = 0.0, best_sdx = 0.0, best_dx_amount = 0.0, best_dy = 0.0, best_sdy = 0.0, best_dy_amount = 0.0, best_unscaled_sdx = 0.0, best_unscaled_sdy = 0.0, rescale_x = 0.0, best_rescale_x = 0.0, best_unscaled_rescale_x = 0.0; FontEntryPtr zero; FontNameRec zeroName; char zeroChars[MAXFONTNAMELEN]; FontDirectoryPtr dir; FontScaledPtr scaled; FontScalableExtraPtr extra; FontScaledPtr best_scaled, best_unscaled; FontPathElementPtr best_fpe = NULL, best_unscaled_fpe = NULL; FontEntryPtr bitmap = NULL; FontEntryPtr result; int aliascount = 20; FontPathElementPtr bitmap_fpe = NULL; FontNameRec xlfdName; /* find the best match */ rescale_x = 1.0; best_scaled = 0; best_score = 0; best_unscaled = 0; best_unscaled_score = -1; best_dx_amount = best_dy_amount = HUGE_VAL; memcpy (zeroChars, entry->name.name, entry->name.length); zeroChars[entry->name.length] = '\0'; zeroName.name = zeroChars; FontParseXLFDName (zeroChars, &temp, FONT_XLFD_REPLACE_ZERO); zeroName.length = strlen (zeroChars); zeroName.ndashes = entry->name.ndashes; xlfdName.name = vals->xlfdName; xlfdName.length = strlen(xlfdName.name); xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length); restart_bestscale_loop: ; /* * Look through all the registered bitmap sources for * the same zero name as ours; entries along that one * can be scaled as desired. */ for (source = 0; source < FontFileBitmapSources.count; source++) { /* There might already be a bitmap that satisfies the request but didn't have a zero name that was found by the scalable font matching logic. Keep track if there is. */ if (bitmap == NULL && vals->xlfdName != NULL) { bitmap_fpe = FontFileBitmapSources.fpe[source]; dir = (FontDirectoryPtr) bitmap_fpe->private; bitmap = FontFileFindNameInDir (&dir->nonScalable, &xlfdName); if (bitmap && bitmap->type != FONT_ENTRY_BITMAP) { if (bitmap->type == FONT_ENTRY_ALIAS && aliascount > 0) { aliascount--; xlfdName.name = bitmap->u.alias.resolved; xlfdName.length = strlen(xlfdName.name); xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length); bitmap = NULL; goto restart_bestscale_loop; } else bitmap = NULL; } } if (FontFileBitmapSources.fpe[source] == fpe) zero = entry; else { dir = (FontDirectoryPtr) FontFileBitmapSources.fpe[source]->private; zero = FontFileFindNameInDir (&dir->scalable, &zeroName); if (!zero) continue; } extra = zero->u.scalable.extra; for (i = 0; i < extra->numScaled; i++) { scaled = &extra->scaled[i]; if (!scaled->bitmap) continue; if (!ComputeScaleFactors(&scaled->vals, vals, &dx, &dy, &sdx, &sdy, &rescale_x)) continue; score = 0; dx_amount = dx; dy_amount = dy; SCORE(dy_amount, 10); SCORE(dx_amount, 1); if ((score > best_score) || ((score == best_score) && ((dy_amount < best_dy_amount) || ((dy_amount == best_dy_amount) && (dx_amount < best_dx_amount))))) { best_fpe = FontFileBitmapSources.fpe[source]; best_scaled = scaled; best_score = score; best_dx = dx; best_dy = dy; best_sdx = sdx; best_sdy = sdy; best_dx_amount = dx_amount; best_dy_amount = dy_amount; best_rescale_x = rescale_x; } /* Is this font a candidate for use without ugly rescaling? */ if (fabs(dx) > EPS && fabs(dy) > EPS && fabs(vals->pixel_matrix[0] * rescale_x - scaled->vals.pixel_matrix[0]) < 1 && fabs(vals->pixel_matrix[1] * rescale_x - scaled->vals.pixel_matrix[1]) < EPS && fabs(vals->pixel_matrix[2] - scaled->vals.pixel_matrix[2]) < EPS && fabs(vals->pixel_matrix[3] - scaled->vals.pixel_matrix[3]) < 1) { /* Yes. The pixel sizes are close on the diagonal and extremely close off the diagonal. */ score = 0; SCORE2(vals->pixel_matrix[3] / scaled->vals.pixel_matrix[3], 10); SCORE2(vals->pixel_matrix[0] * rescale_x / scaled->vals.pixel_matrix[0], 1); if (score > best_unscaled_score) { best_unscaled_fpe = FontFileBitmapSources.fpe[source]; best_unscaled = scaled; best_unscaled_sdx = sdx / dx; best_unscaled_sdy = sdy / dy; best_unscaled_score = score; best_unscaled_rescale_x = rescale_x; } } } } if (best_unscaled) { *best = best_unscaled->vals; *fpep = best_unscaled_fpe; *dxp = 1.0; *dyp = 1.0; *sdxp = best_unscaled_sdx; *sdyp = best_unscaled_sdy; rescale_x = best_unscaled_rescale_x; result = best_unscaled->bitmap; } else if (best_scaled) { *best = best_scaled->vals; *fpep = best_fpe; *dxp = best_dx; *dyp = best_dy; *sdxp = best_sdx; *sdyp = best_sdy; rescale_x = best_rescale_x; result = best_scaled->bitmap; } else result = NULL; if (bitmap != NULL && (result == NULL || *dxp != 1.0 || *dyp != 1.0)) { *fpep = bitmap_fpe; FontParseXLFDName (bitmap->name.name, best, FONT_XLFD_REPLACE_NONE); if (ComputeScaleFactors(best, best, dxp, dyp, sdxp, sdyp, &rescale_x)) result = bitmap; else result = NULL; } if (result && rescale_x != 1.0) { /* We have rescaled horizontally due to an XLFD width field. Change the matrix appropriately */ vals->pixel_matrix[0] *= rescale_x; vals->pixel_matrix[1] *= rescale_x; #ifdef NOTDEF /* This would force the pointsize and pixelsize fields in the FONT property to display as matrices to more accurately report the font being supplied. It might also break existing applications that expect a single number in that field. */ vals->values_supplied = vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) | PIXELSIZE_ARRAY; #else /* NOTDEF */ vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK; #endif /* NOTDEF */ /* Recompute and reround the FontScalablePtr values after rescaling for the new width. */ FontFileCompleteXLFD(vals, vals); } return result; } static FontEntryPtr FindPmfToScale(FontPathElementPtr fpe, FontEntryPtr entry, FontScalablePtr vals, FontScalablePtr best, double *dxp, double *dyp, double *sdxp, double *sdyp, FontPathElementPtr *fpep) { FontEntryPtr result = NULL; FontScaledPtr scaled; FontScalableExtraPtr extra; int i; extra = entry->u.scalable.extra; for (i = 0; i < extra->numScaled; i++) { double rescale_x; scaled = &extra->scaled[i]; if (!scaled->bitmap) continue; if (!ComputeScaleFactors(&scaled->vals, vals, dxp, dyp, sdxp, sdyp, &rescale_x)) continue; *best = scaled->vals; *fpep = fpe; result = scaled->bitmap; if (rescale_x != 1.0) { /* We have rescaled horizontally due to an XLFD width field. Change the matrix appropriately */ vals->pixel_matrix[0] *= rescale_x; vals->pixel_matrix[1] *= rescale_x; #ifdef NOTDEF /* This would force the pointsize and pixelsize fields in the FONT property to display as matrices to more accurately report the font being supplied. It might also break existing applications that expect a single number in that field. */ vals->values_supplied = vals->values_supplied & ~(PIXELSIZE_MASK | POINTSIZE_MASK) | PIXELSIZE_ARRAY; #else /* NOTDEF */ vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK; #endif /* NOTDEF */ /* Recompute and reround the FontScalablePtr values after rescaling for the new width. */ FontFileCompleteXLFD(vals, vals); } break; } return result; } static long doround(double x) { return (x >= 0) ? (long)(x + .5) : (long)(x - .5); } static int computeProps(FontPropPtr pf, char *wasStringProp, FontPropPtr npf, char *isStringProp, unsigned int nprops, double xfactor, double yfactor, double sXfactor, double sYfactor) { int n; int count; fontProp *t; double rawfactor = 0.0; for (count = 0; nprops > 0; nprops--, pf++, wasStringProp++) { n = sizeof(fontPropTable) / sizeof(fontProp); for (t = fontPropTable; n && (t->atom != pf->name); n--, t++); if (!n) continue; switch (t->type) { case scaledX: npf->value = doround(xfactor * (double)pf->value); rawfactor = sXfactor; break; case scaledY: npf->value = doround(yfactor * (double)pf->value); rawfactor = sYfactor; break; case unscaled: npf->value = pf->value; npf->name = pf->name; npf++; count++; *isStringProp++ = *wasStringProp; break; default: break; } if (t->type != unscaled) { npf->name = pf->name; npf++; count++; npf->value = doround(rawfactor * (double)pf->value); npf->name = rawFontPropTable[t - fontPropTable].atom; npf++; count++; *isStringProp++ = *wasStringProp; *isStringProp++ = *wasStringProp; } } return count; } static int ComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the font to be scaled */ char *name, /* name of resulting font */ FontScalablePtr vals, double dx, double dy, /* scale factors in x and y */ double sdx, double sdy, /* directions */ long sWidth, /* 1000-pixel average width */ FontPropPtr *pProps, /* returns properties; preallocated */ char **pIsStringProp) /* return booleans; preallocated */ { int n; char *ptr1 = NULL, *ptr2 = NULL; char *ptr3; FontPropPtr fp; fontProp *fpt; char *isStringProp; int nProps; if (bitscaleGeneration != serverGeneration) { initFontPropTable(); bitscaleGeneration = serverGeneration; } nProps = NPROPS + 1 + sizeof(fontPropTable) / sizeof(fontProp) + sizeof(rawFontPropTable) / sizeof(fontProp); fp = (FontPropPtr) xalloc(sizeof(FontPropRec) * nProps); *pProps = fp; if (!fp) { fprintf(stderr, "Error: Couldn't allocate font properties (%ld*%d)\n", (unsigned long)sizeof(FontPropRec), nProps); return 1; } isStringProp = (char *) xalloc (nProps); *pIsStringProp = isStringProp; if (!isStringProp) { fprintf(stderr, "Error: Couldn't allocate isStringProp (%d)\n", nProps); xfree (fp); return 1; } ptr2 = name; for (fpt = fontNamePropTable, n = NPROPS; n; fp++, fpt++, n--, isStringProp++) { if (*ptr2) { ptr1 = ptr2 + 1; if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0'); } *isStringProp = 0; switch (fpt->type) { case atom: fp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE); *isStringProp = 1; break; case truncate_atom: for (ptr3 = ptr1; *ptr3; ptr3++) if (*ptr3 == '[') break; if (!*ptr3) ptr3 = ptr2; fp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE); *isStringProp = 1; break; case pixel_size: fp->value = doround(vals->pixel_matrix[3]); break; case point_size: fp->value = doround(vals->point_matrix[3] * 10.0); break; case resolution_x: fp->value = vals->x; break; case resolution_y: fp->value = vals->y; break; case average_width: fp->value = vals->width; break; case fontname: fp->value = MakeAtom(name, strlen(name), TRUE); *isStringProp = 1; break; case raw_ascent: fp->value = sourceFontInfo->fontAscent * sdy; break; case raw_descent: fp->value = sourceFontInfo->fontDescent * sdy; break; case raw_pointsize: fp->value = (long)(72270.0 / (double)vals->y + .5); break; case raw_pixelsize: fp->value = 1000; break; case raw_average_width: fp->value = sWidth; break; default: break; } fp->name = fpt->atom; } n = NPROPS; n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp, fp, isStringProp, sourceFontInfo->nprops, dx, dy, sdx, sdy); return n; } static int compute_xform_matrix(FontScalablePtr vals, double dx, double dy, double *xform, double *inv_xform, double *xmult, double *ymult) { double det; double pixel = get_matrix_vertical_component(vals->pixel_matrix); double pixelset = get_matrix_horizontal_component(vals->pixel_matrix); if (pixel < EPS || pixelset < EPS) return 0; /* Initialize the transformation matrix to the scaling factors */ xform[0] = dx / pixelset; xform[1] = xform[2] = 0.0; xform[3] = dy / pixel; /* Inline matrix multiply -- somewhat ugly to minimize register usage */ #define MULTIPLY_XFORM(a,b,c,d) \ { \ register double aa = (a), bb = (b), cc = (c), dd = (d); \ register double temp; \ temp = aa * xform[0] + cc * xform[1]; \ aa = aa * xform[2] + cc * xform[3]; \ xform[1] = bb * xform[0] + dd * xform[1]; \ xform[3] = bb * xform[2] + dd * xform[3]; \ xform[0] = temp; \ xform[2] = aa; \ } /* Rescale the transformation matrix for size of source font */ MULTIPLY_XFORM(vals->pixel_matrix[0], vals->pixel_matrix[1], vals->pixel_matrix[2], vals->pixel_matrix[3]); *xmult = xform[0]; *ymult = xform[3]; if (inv_xform == NULL) return 1; /* Compute the determinant for use in inverting the matrix. */ det = xform[0] * xform[3] - xform[1] * xform[2]; /* If the determinant is tiny or zero, give up */ if (fabs(det) < EPS) return 0; /* Compute the inverse */ inv_xform[0] = xform[3] / det; inv_xform[1] = -xform[1] / det; inv_xform[2] = -xform[2] / det; inv_xform[3] = xform[0] / det; return 1; } /* * ScaleFont * returns a pointer to the new scaled font, or NULL (due to AllocError). */ static FontPtr ScaleFont(FontPtr opf, /* originating font */ double widthMult, /* glyphs width scale factor */ double heightMult, /* glyphs height scale factor */ double sWidthMult, /* scalable glyphs width scale factor */ double sHeightMult, /* scalable glyphs height scale factor */ FontScalablePtr vals, double *newWidthMult, /* return: X component of glyphs width scale factor */ double *newHeightMult, /* return: Y component of glyphs height scale factor */ long *sWidth) /* return: average 1000-pixel width */ { FontPtr pf; FontInfoPtr pfi, opfi; BitmapFontPtr bitmapFont, obitmapFont; CharInfoPtr pci, opci; int nchars = 0; /* how many characters in the font */ int i; int firstCol, lastCol, firstRow, lastRow; double xform[4], inv_xform[4]; double xmult, ymult; int totalwidth = 0, totalchars = 0; #define OLDINDEX(i) (((i)/(lastCol - firstCol + 1) + \ firstRow - opf->info.firstRow) * \ (opf->info.lastCol - opf->info.firstCol + 1) + \ (i)%(lastCol - firstCol + 1) + \ firstCol - opf->info.firstCol) *sWidth = 0; opfi = &opf->info; obitmapFont = (BitmapFontPtr) opf->fontPrivate; bitmapFont = 0; if (!(pf = CreateFontRec())) { fprintf(stderr, "Error: Couldn't allocate FontRec (%ld)\n", (unsigned long)sizeof(FontRec)); goto bail; } pf->refcnt = 0; pf->bit = opf->bit; pf->byte = opf->byte; pf->glyph = opf->glyph; pf->scan = opf->scan; pf->get_glyphs = bitmapGetGlyphs; pf->get_metrics = bitmapGetMetrics; pf->unload_font = bitmapUnloadScalable; pf->unload_glyphs = NULL; pfi = &pf->info; *pfi = *opfi; /* If charset subsetting specified in vals, determine what our range needs to be for the output font */ if (vals->nranges) { int i; pfi->allExist = 0; firstCol = 255; lastCol = 0; firstRow = 255; lastRow = 0; for (i = 0; i < vals->nranges; i++) { if (vals->ranges[i].min_char_high != vals->ranges[i].max_char_high) { firstCol = opfi->firstCol; lastCol = opfi->lastCol; } if (firstCol > vals->ranges[i].min_char_low) firstCol = vals->ranges[i].min_char_low; if (lastCol < vals->ranges[i].max_char_low) lastCol = vals->ranges[i].max_char_low; if (firstRow > vals->ranges[i].min_char_high) firstRow = vals->ranges[i].min_char_high; if (lastRow < vals->ranges[i].max_char_high) lastRow = vals->ranges[i].max_char_high; } if (firstCol > lastCol || firstRow > lastRow) goto bail; if (firstCol < opfi->firstCol) firstCol = opfi->firstCol; if (lastCol > opfi->lastCol) lastCol = opfi->lastCol; if (firstRow < opfi->firstRow) firstRow = opfi->firstRow; if (lastRow > opfi->lastRow) lastRow = opfi->lastRow; } else { firstCol = opfi->firstCol; lastCol = opfi->lastCol; firstRow = opfi->firstRow; lastRow = opfi->lastRow; } bitmapFont = (BitmapFontPtr) xalloc(sizeof(BitmapFontRec)); if (!bitmapFont) { fprintf(stderr, "Error: Couldn't allocate bitmapFont (%ld)\n", (unsigned long)sizeof(BitmapFontRec)); goto bail; } nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); pfi->firstRow = firstRow; pfi->lastRow = lastRow; pfi->firstCol = firstCol; pfi->lastCol = lastCol; pf->fontPrivate = (pointer) bitmapFont; bitmapFont->version_num = obitmapFont->version_num; bitmapFont->num_chars = nchars; bitmapFont->num_tables = obitmapFont->num_tables; bitmapFont->metrics = 0; bitmapFont->ink_metrics = 0; bitmapFont->bitmaps = 0; bitmapFont->encoding = 0; bitmapFont->bitmapExtra = 0; bitmapFont->pDefault = 0; bitmapFont->metrics = (CharInfoPtr) xalloc(nchars * sizeof(CharInfoRec)); if (!bitmapFont->metrics) { fprintf(stderr, "Error: Couldn't allocate metrics (%d*%ld)\n", nchars, (unsigned long)sizeof(CharInfoRec)); goto bail; } bitmapFont->encoding = (CharInfoPtr **) xcalloc(NUM_SEGMENTS(nchars), sizeof(CharInfoPtr*)); if (!bitmapFont->encoding) { fprintf(stderr, "Error: Couldn't allocate encoding (%d*%ld)\n", nchars, (unsigned long)sizeof(CharInfoPtr)); goto bail; } #undef MAXSHORT #define MAXSHORT 32767 #undef MINSHORT #define MINSHORT -32768 pfi->anamorphic = FALSE; if (heightMult != widthMult) pfi->anamorphic = TRUE; pfi->cachable = TRUE; if (!compute_xform_matrix(vals, widthMult, heightMult, xform, inv_xform, &xmult, &ymult)) goto bail; pfi->fontAscent = opfi->fontAscent * ymult; pfi->fontDescent = opfi->fontDescent * ymult; pfi->minbounds.leftSideBearing = MAXSHORT; pfi->minbounds.rightSideBearing = MAXSHORT; pfi->minbounds.ascent = MAXSHORT; pfi->minbounds.descent = MAXSHORT; pfi->minbounds.characterWidth = MAXSHORT; pfi->minbounds.attributes = MAXSHORT; pfi->maxbounds.leftSideBearing = MINSHORT; pfi->maxbounds.rightSideBearing = MINSHORT; pfi->maxbounds.ascent = MINSHORT; pfi->maxbounds.descent = MINSHORT; pfi->maxbounds.characterWidth = MINSHORT; pfi->maxbounds.attributes = MINSHORT; /* Compute the transformation and inverse transformation matrices. Can fail if the determinant is zero. */ pci = bitmapFont->metrics; for (i = 0; i < nchars; i++) { if ((opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i)))) { double newlsb, newrsb, newdesc, newasc, point[2]; #define minchar(p) ((p).min_char_low + ((p).min_char_high << 8)) #define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8)) if (vals->nranges) { int row = i / (lastCol - firstCol + 1) + firstRow; int col = i % (lastCol - firstCol + 1) + firstCol; int ch = (row << 8) + col; int j; for (j = 0; j < vals->nranges; j++) if (ch >= minchar(vals->ranges[j]) && ch <= maxchar(vals->ranges[j])) break; if (j == vals->nranges) { continue; } } if (opci->metrics.leftSideBearing == 0 && opci->metrics.rightSideBearing == 0 && opci->metrics.ascent == 0 && opci->metrics.descent == 0 && opci->metrics.characterWidth == 0) { continue; } if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) { bitmapFont->encoding[SEGMENT_MAJOR(i)]= (CharInfoPtr*)xcalloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr)); if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) goto bail; } ACCESSENCODINGL(bitmapFont->encoding, i) = pci; /* Compute new extents for this glyph */ TRANSFORM_POINT(xform, opci->metrics.leftSideBearing, -opci->metrics.descent, point); newlsb = point[0]; newrsb = newlsb; newdesc = -point[1]; newasc = -newdesc; TRANSFORM_POINT(xform, opci->metrics.leftSideBearing, opci->metrics.ascent, point); CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); TRANSFORM_POINT(xform, opci->metrics.rightSideBearing, -opci->metrics.descent, point); CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); TRANSFORM_POINT(xform, opci->metrics.rightSideBearing, opci->metrics.ascent, point); CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); pci->metrics.leftSideBearing = (int)floor(newlsb); pci->metrics.rightSideBearing = (int)floor(newrsb + .5); pci->metrics.descent = (int)ceil(newdesc); pci->metrics.ascent = (int)floor(newasc + .5); /* Accumulate total width of characters before transformation, to ascertain predominant direction of font. */ totalwidth += opci->metrics.characterWidth; pci->metrics.characterWidth = doround((double)opci->metrics.characterWidth * xmult); pci->metrics.attributes = doround((double)opci->metrics.characterWidth * sWidthMult); if (!pci->metrics.characterWidth) { /* Since transformation may shrink width, height, and escapement to zero, make sure existing characters are not mistaken for undefined characters. */ if (pci->metrics.rightSideBearing == pci->metrics.leftSideBearing) pci->metrics.rightSideBearing++; if (pci->metrics.ascent == -pci->metrics.descent) pci->metrics.ascent++; } pci++; } } /* * For each character, set the per-character metrics, scale the glyph, and * check per-font minbounds and maxbounds character information. */ pci = bitmapFont->metrics; for (i = 0; i < nchars; i++) { if ((pci = ACCESSENCODING(bitmapFont->encoding,i)) && (opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i)))) { totalchars++; *sWidth += abs((int)(INT16)pci->metrics.attributes); #define MINMAX(field) \ if (pfi->minbounds.field > pci->metrics.field) \ pfi->minbounds.field = pci->metrics.field; \ if (pfi->maxbounds.field < pci->metrics.field) \ pfi->maxbounds.field = pci->metrics.field MINMAX(leftSideBearing); MINMAX(rightSideBearing); MINMAX(ascent); MINMAX(descent); MINMAX(characterWidth); /* Hack: Cast attributes into a signed quantity. Tread lightly for now and don't go changing the global Xproto.h file */ if ((INT16)pfi->minbounds.attributes > (INT16)pci->metrics.attributes) pfi->minbounds.attributes = pci->metrics.attributes; if ((INT16)pfi->maxbounds.attributes < (INT16)pci->metrics.attributes) pfi->maxbounds.attributes = pci->metrics.attributes; #undef MINMAX } } pfi->ink_minbounds = pfi->minbounds; pfi->ink_maxbounds = pfi->maxbounds; if (totalchars) { *sWidth = (*sWidth * 10 + totalchars / 2) / totalchars; if (totalwidth < 0) { /* Dominant direction is R->L */ *sWidth = -*sWidth; } if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth) vals->width = pfi->minbounds.characterWidth * 10; else vals->width = doround((double)*sWidth * vals->pixel_matrix[0] / 1000.0); } else { vals->width = 0; *sWidth = 0; } FontComputeInfoAccelerators (pfi); if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) { unsigned int r, c, cols; r = pfi->defaultCh >> 8; c = pfi->defaultCh & 0xFF; if (pfi->firstRow <= r && r <= pfi->lastRow && pfi->firstCol <= c && c <= pfi->lastCol) { cols = pfi->lastCol - pfi->firstCol + 1; r = r - pfi->firstRow; c = c - pfi->firstCol; bitmapFont->pDefault = ACCESSENCODING(bitmapFont->encoding, r * cols + c); } } *newWidthMult = xmult; *newHeightMult = ymult; return pf; bail: if (pf) xfree(pf); if (bitmapFont) { xfree(bitmapFont->metrics); xfree(bitmapFont->ink_metrics); xfree(bitmapFont->bitmaps); if(bitmapFont->encoding) for(i=0; i<NUM_SEGMENTS(nchars); i++) xfree(bitmapFont->encoding[i]); xfree(bitmapFont->encoding); } return NULL; } static void ScaleBitmap(FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci, double *inv_xform, double widthMult, double heightMult) { register char *bitmap, /* The bits */ *newBitmap; register int bpr, /* Padding information */ newBpr; int width, /* Extents information */ height, newWidth, newHeight; register int row, /* Loop variables */ col; INT32 deltaX, /* Increments for resampling loop */ deltaY; INT32 xValue, /* Subscripts for resampling loop */ yValue; double point[2]; unsigned char *char_grayscale = 0; INT32 *diffusion_workspace = NULL, *thisrow = NULL, *nextrow = NULL, pixmult = 0; int box_x = 0, box_y = 0; static unsigned char masklsb[] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 }; static unsigned char maskmsb[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; unsigned char *mask = (pFont->bit == LSBFirst ? masklsb : maskmsb); bitmap = opci->bits; newBitmap = pci->bits; width = GLYPHWIDTHPIXELS(opci); height = GLYPHHEIGHTPIXELS(opci); newWidth = GLYPHWIDTHPIXELS(pci); newHeight = GLYPHHEIGHTPIXELS(pci); if (!newWidth || !newHeight || !width || !height) return; bpr = BYTES_PER_ROW(width, pFont->glyph); newBpr = BYTES_PER_ROW(newWidth, pFont->glyph); if (widthMult > 0.0 && heightMult > 0.0 && (widthMult < 1.0 || heightMult < 1.0)) { /* We are reducing in one or both dimensions. In an attempt to reduce aliasing, we'll antialias by passing the original glyph through a low-pass box filter (which results in a grayscale image), then use error diffusion to create bitonal output in the resampling loop. */ /* First compute the sizes of the box filter */ widthMult = ceil(1.0 / widthMult); heightMult = ceil(1.0 / heightMult); box_x = width / 2; box_y = height / 2; if (widthMult < (double)box_x) box_x = (int)widthMult; if (heightMult < (double)box_y) box_y = (int)heightMult; /* The pixmult value (below) is used to darken the image before we perform error diffusion: a necessary concession to the fact that it's very difficult to generate readable halftoned glyphs. The degree of darkening is proportional to the size of the blurring filter, hence inversely proportional to the darkness of the lightest gray that results from antialiasing. The result is that characters that exercise this logic (those generated by reducing from a larger source font) tend to err on the side of being too bold instead of being too light to be readable. */ pixmult = box_x * box_y * 192; if (box_x > 1 || box_y > 1) { /* Looks like we need to anti-alias. Create a workspace to contain the grayscale character plus an additional row and column for scratch */ char_grayscale = (unsigned char *)xalloc((width + 1) * (height + 1)); if (char_grayscale) { diffusion_workspace = (INT32 *)xalloc((newWidth + 2) * 2 * sizeof(int)); if (!diffusion_workspace) { fprintf(stderr, "Warning: Couldn't allocate diffusion" " workspace (%ld)\n", (newWidth + 2) * 2 * (unsigned long)sizeof(int)); xfree(char_grayscale); char_grayscale = (unsigned char *)0; } /* Initialize our error diffusion workspace for later use */ bzero((char *)diffusion_workspace + sizeof(INT32), (newWidth + 3) * sizeof(int)); thisrow = diffusion_workspace + 1; nextrow = diffusion_workspace + newWidth + 3; } else { fprintf(stderr, "Warning: Couldn't allocate character grayscale (%d)\n", (width + 1) * (height + 1)); } } } if (char_grayscale) { /* We will be doing antialiasing. First copy the bitmap into our buffer, mapping input range [0,1] to output range [0,255]. */ register unsigned char *srcptr, *dstptr; srcptr = (unsigned char *)bitmap; dstptr = char_grayscale; for (row = 0; row < height; row++) { for (col = 0; col < width; col++) *dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0; srcptr += bpr; /* On to next row of source */ dstptr++; /* Skip scratch column in dest */ } if (box_x > 1) { /* Our box filter has a width > 1... let's filter the rows */ int right_width = box_x / 2; int left_width = box_x - right_width - 1; for (row = 0; row < height; row++) { int sum = 0; int left_size = 0, right_size = 0; srcptr = char_grayscale + (width + 1) * row; dstptr = char_grayscale + (width + 1) * height; /* scratch */ /* We've computed the shape of our full box filter. Now compute the right-hand part of the moving sum */ for (right_size = 0; right_size < right_width; right_size++) sum += srcptr[right_size]; /* Now start moving the sum, growing the box filter, and dropping averages into our scratch buffer */ for (left_size = 0; left_size < left_width; left_size++) { sum += srcptr[right_width]; *dstptr++ = sum / (left_size + right_width + 1); srcptr++; } /* The box filter has reached full width... continue computation of moving average until the right side hits the wall. */ for (col = left_size; col + right_size < width; col++) { sum += srcptr[right_width]; *dstptr++ = sum / box_x; sum -= srcptr[-left_width]; srcptr++; } /* Collapse the right side of the box filter */ for (; right_size > 0; right_size--) { *dstptr++ = sum / (left_width + right_size); sum -= srcptr[-left_width]; srcptr++; } /* Done with the row... copy dest back over source */ memmove(char_grayscale + (width + 1) * row, char_grayscale + (width + 1) * height, width); } } if (box_y > 1) { /* Our box filter has a height > 1... let's filter the columns */ int bottom_height = box_y / 2; int top_height = box_y - bottom_height - 1; for (col = 0; col < width; col++) { int sum = 0; int top_size = 0, bottom_size = 0; srcptr = char_grayscale + col; dstptr = char_grayscale + width; /* scratch */ /* We've computed the shape of our full box filter. Now compute the bottom part of the moving sum */ for (bottom_size = 0; bottom_size < bottom_height; bottom_size++) sum += srcptr[bottom_size * (width + 1)]; /* Now start moving the sum, growing the box filter, and dropping averages into our scratch buffer */ for (top_size = 0; top_size < top_height; top_size++) { sum += srcptr[bottom_height * (width + 1)]; *dstptr = sum / (top_size + bottom_height + 1); dstptr += width + 1; srcptr += width + 1; } /* The box filter has reached full height... continue computation of moving average until the bottom hits the wall. */ for (row = top_size; row + bottom_size < height; row++) { sum += srcptr[bottom_height * (width + 1)]; *dstptr = sum / box_y; dstptr += width + 1; sum -= srcptr[-top_height * (width + 1)]; srcptr += width + 1; } /* Collapse the bottom of the box filter */ for (; bottom_size > 0; bottom_size--) { *dstptr = sum / (top_height + bottom_size); dstptr += width + 1; sum -= srcptr[-top_height * (width + 1)]; srcptr += width + 1; } /* Done with the column... copy dest back over source */ dstptr = char_grayscale + col; srcptr = char_grayscale + width; /* scratch */ for (row = 0; row < height; row++) { *dstptr = *srcptr; dstptr += width + 1; srcptr += width + 1; } } } /* Increase the grayvalue to increase ink a bit */ srcptr = char_grayscale; for (row = 0; row < height; row++) { for (col = 0; col < width; col++) { register int pixvalue = (int)*srcptr * pixmult / 256; if (pixvalue > 255) pixvalue = 255; *srcptr = pixvalue; srcptr++; } srcptr++; } } /* Compute the increment values for the resampling loop */ TRANSFORM_POINT(inv_xform, 1, 0, point); deltaX = (INT32)(point[0] * 65536.0); deltaY = (INT32)(-point[1] * 65536.0); /* Resampling loop: resamples original glyph for generation of new glyph in transformed coordinate system. */ for (row = 0; row < newHeight; row++) { /* Compute inverse transformation for start of this row */ TRANSFORM_POINT(inv_xform, (double)(pci->metrics.leftSideBearing) + .5, (double)(pci->metrics.ascent - row) - .5, point); /* Adjust for coordinate system to get resampling point */ point[0] -= opci->metrics.leftSideBearing; point[1] = opci->metrics.ascent - point[1]; /* Convert to integer coordinates */ xValue = (INT32)(point[0] * 65536.0); yValue = (INT32)(point[1] * 65536.0); if (char_grayscale) { INT32 *temp; for (col = 0; col < newWidth; col++) { register int x = xValue >> 16, y = yValue >> 16; int pixvalue, error; pixvalue = ((x >= 0 && x < width && y >= 0 && y < height) ? char_grayscale[x + y * (width + 1)] : 0) + thisrow[col] / 16; if (pixvalue > 255) pixvalue = 255; else if (pixvalue < 0) pixvalue = 0; /* Choose the bit value and set resulting error value */ if (pixvalue >= 128) { newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7]; error = pixvalue - 255; } else error = -pixvalue; /* Diffuse the error */ thisrow[col + 1] += error * 7; nextrow[col - 1] += error * 3; nextrow[col] += error * 5; nextrow[col + 1] = error; xValue += deltaX; yValue += deltaY; } /* Add in error values that fell off either end */ nextrow[0] += nextrow[-1]; nextrow[newWidth - 2] += thisrow[newWidth]; nextrow[newWidth - 1] += nextrow[newWidth]; nextrow[newWidth] = 0; temp = nextrow; nextrow = thisrow; thisrow = temp; nextrow[-1] = nextrow[0] = 0; } else { for (col = 0; col < newWidth; col++) { register int x = xValue >> 16, y = yValue >> 16; if (x >= 0 && x < width && y >= 0 && y < height) { /* Use point-sampling for rescaling. */ if (bitmap[(x >> 3) + y * bpr] & mask[x & 0x7]) newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7]; } xValue += deltaX; yValue += deltaY; } } } if (char_grayscale) { xfree(char_grayscale); xfree(diffusion_workspace); } } static FontPtr BitmapScaleBitmaps(FontPtr pf, /* scaled font */ FontPtr opf, /* originating font */ double widthMult, /* glyphs width scale factor */ double heightMult, /* glyphs height scale factor */ FontScalablePtr vals) { register int i; int nchars = 0; char *glyphBytes; BitmapFontPtr bitmapFont, obitmapFont; CharInfoPtr pci, opci; FontInfoPtr pfi; int glyph; unsigned bytestoalloc = 0; int firstCol, lastCol, firstRow, lastRow; double xform[4], inv_xform[4]; double xmult, ymult; bitmapFont = (BitmapFontPtr) pf->fontPrivate; obitmapFont = (BitmapFontPtr) opf->fontPrivate; if (!compute_xform_matrix(vals, widthMult, heightMult, xform, inv_xform, &xmult, &ymult)) goto bail; pfi = &pf->info; firstCol = pfi->firstCol; lastCol = pfi->lastCol; firstRow = pfi->firstRow; lastRow = pfi->lastRow; nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); glyph = pf->glyph; for (i = 0; i < nchars; i++) { if ((pci = ACCESSENCODING(bitmapFont->encoding, i))) bytestoalloc += BYTES_FOR_GLYPH(pci, glyph); } /* Do we add the font malloc stuff for VALUE ADDED ? */ /* Will need to remember to free in the Unload routine */ bitmapFont->bitmaps = (char *) xalloc(bytestoalloc); if (!bitmapFont->bitmaps) { fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc); goto bail; } bzero(bitmapFont->bitmaps, bytestoalloc); glyphBytes = bitmapFont->bitmaps; for (i = 0; i < nchars; i++) { if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) && (opci = ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i)))) { pci->bits = glyphBytes; ScaleBitmap (pf, opci, pci, inv_xform, widthMult, heightMult); glyphBytes += BYTES_FOR_GLYPH(pci, glyph); } } return pf; bail: if (pf) xfree(pf); if (bitmapFont) { xfree(bitmapFont->metrics); xfree(bitmapFont->ink_metrics); xfree(bitmapFont->bitmaps); if(bitmapFont->encoding) for(i=0; i<NUM_SEGMENTS(nchars); i++) xfree(bitmapFont->encoding[i]); xfree(bitmapFont->encoding); } return NULL; } static FontPtr PrinterScaleBitmaps(FontPtr pf, /* scaled font */ FontPtr opf, /* originating font */ double widthMult, /* glyphs width scale factor */ double heightMult, /* glyphs height scale factor */ FontScalablePtr vals) { register int i; int nchars = 0; char *glyphBytes; BitmapFontPtr bitmapFont, obitmapFont; CharInfoPtr pci; FontInfoPtr pfi; int glyph; unsigned bytestoalloc = 0; int firstCol, lastCol, firstRow, lastRow; double xform[4], inv_xform[4]; double xmult, ymult; bitmapFont = (BitmapFontPtr) pf->fontPrivate; obitmapFont = (BitmapFontPtr) opf->fontPrivate; if (!compute_xform_matrix(vals, widthMult, heightMult, xform, inv_xform, &xmult, &ymult)) goto bail; pfi = &pf->info; firstCol = pfi->firstCol; lastCol = pfi->lastCol; firstRow = pfi->firstRow; lastRow = pfi->lastRow; nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); glyph = pf->glyph; for (i = 0; i < nchars; i++) { if ((pci = ACCESSENCODING(bitmapFont->encoding, i))) bytestoalloc = MAX(bytestoalloc,BYTES_FOR_GLYPH(pci, glyph)); } /* Do we add the font malloc stuff for VALUE ADDED ? */ /* Will need to remember to free in the Unload routine */ bitmapFont->bitmaps = (char *) xalloc(bytestoalloc); if (!bitmapFont->bitmaps) { fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc); goto bail; } bzero(bitmapFont->bitmaps, bytestoalloc); glyphBytes = bitmapFont->bitmaps; for (i = 0; i < nchars; i++) { if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) && (ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i)))) { pci->bits = glyphBytes; } } return pf; bail: if (pf) xfree(pf); if (bitmapFont) { xfree(bitmapFont->metrics); xfree(bitmapFont->ink_metrics); xfree(bitmapFont->bitmaps); if(bitmapFont->encoding) for(i=0; i<NUM_SEGMENTS(nchars); i++) xfree(bitmapFont->encoding[i]); xfree(bitmapFont->encoding); } return NULL; } #ifdef NOTDEF /* * exported interfaces */ FontFileLoadName(FontFileDirPtr *dirs, int ndirs, char *name, FontPtr *pfont, fsBitmapFormat format, fsBitmapFormatMask fmask) { FontFileNamePtr fname; char full_name[1024]; int ret = BadFontName; int i; i = 0; while (i < ndirs) { if (fname = FontFileFindNameInDir(dirs[i], name)) { if (!fname->alias) { if (!fname->font) { strcpy(full_name, dirs[i]->dir); strcat(full_name, fname->file); ret = FontFileLoad(pfont, full_name, format, fmask); if (ret == Successful) { fname->font = *pfont; (*pfont)->fpePrivate = (pointer) fname; } return ret; } *pfont = fname->font; return Successful; } name = fname->file; i = 0; } else i++; } return BadFontName; } #endif /* ARGSUSED */ int BitmapOpenScalable (FontPathElementPtr fpe, FontPtr *pFont, int flags, FontEntryPtr entry, char *fileName, /* unused */ FontScalablePtr vals, fsBitmapFormat format, fsBitmapFormatMask fmask, FontPtr non_cachable_font) /* We don't do licensing */ { FontScalableRec best; FontPtr font = NullFont; double dx, sdx, dy, sdy, savedX, savedY; FontPropPtr props; char *isStringProp; int propCount; int status; long sWidth; FontEntryPtr scaleFrom; FontPathElementPtr scaleFPE; FontPtr sourceFont; char fontName[MAXFONTNAMELEN]; /* Can't deal with mix-endian fonts yet */ #ifdef NOTDEF /* XXX need better test */ if ((format & BitmapFormatByteOrderMask) != (format & BitmapFormatBitOrderMask)) return NullFontFileName; #endif /* Reject outrageously small font sizes to keep the math from blowing up. */ if (get_matrix_vertical_component(vals->pixel_matrix) < 1.0 || get_matrix_horizontal_component(vals->pixel_matrix) < 1.0) return BadFontName; scaleFrom = (*find_scale[BitmapGetRenderIndex(entry->u.bitmap.renderer)]) (fpe, entry, vals, &best, &dx, &dy, &sdx, &sdy, &scaleFPE); if (!scaleFrom) return BadFontName; status = FontFileOpenBitmap(scaleFPE, &sourceFont, LoadAll, scaleFrom, format, fmask); if (status != Successful) return BadFontName; if (!vals->width) vals->width = best.width * dx; /* Compute the scaled font */ savedX = dx; savedY = dy; font = ScaleFont(sourceFont, dx, dy, sdx, sdy, vals, &dx, &dy, &sWidth); if (font) font = (*scale[ BitmapGetRenderIndex(entry->u.bitmap.renderer) ]) (font, sourceFont, savedX, savedY, vals); if (!font) { if (!sourceFont->refcnt) FontFileCloseFont((FontPathElementPtr) 0, sourceFont); return AllocError; } /* Prepare font properties for the new font */ strcpy (fontName, scaleFrom->name.name); FontParseXLFDName (fontName, vals, FONT_XLFD_REPLACE_VALUE); propCount = ComputeScaledProperties(&sourceFont->info, fontName, vals, dx, dy, sdx, sdy, sWidth, &props, &isStringProp); if (!sourceFont->refcnt) FontFileCloseFont((FontPathElementPtr) 0, sourceFont); if (propCount && (!props || !isStringProp)) { font->info.nprops = 0; font->info.props = (FontPropPtr)0; font->info.isStringProp = (char *)0; bitmapUnloadScalable(font); return AllocError; } font->info.props = props; font->info.nprops = propCount; font->info.isStringProp = isStringProp; *pFont = font; return Successful; } int BitmapGetInfoScalable (FontPathElementPtr fpe, FontInfoPtr pFontInfo, FontEntryPtr entry, FontNamePtr fontName, char *fileName, FontScalablePtr vals) { FontPtr pfont; int flags = 0; long format = 0; /* It doesn't matter what format for just info */ long fmask = 0; int ret; ret = BitmapOpenScalable(fpe, &pfont, flags, entry, fileName, vals, format, fmask, NULL); if (ret != Successful) return ret; *pFontInfo = pfont->info; pfont->info.nprops = 0; pfont->info.props = NULL; pfont->info.isStringProp = NULL; (*pfont->unload_font)(pfont); return Successful; } static void bitmapUnloadScalable (FontPtr pFont) { BitmapFontPtr bitmapFont; FontInfoPtr pfi; int i, nencoding; bitmapFont = (BitmapFontPtr) pFont->fontPrivate; pfi = &pFont->info; xfree (pfi->props); xfree (pfi->isStringProp); if(bitmapFont->encoding) { nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) * (pFont->info.lastRow - pFont->info.firstRow + 1); for(i=0; i<NUM_SEGMENTS(nencoding); i++) xfree(bitmapFont->encoding[i]); } xfree (bitmapFont->encoding); xfree (bitmapFont->bitmaps); xfree (bitmapFont->ink_metrics); xfree (bitmapFont->metrics); xfree (pFont->fontPrivate); DestroyFontRec (pFont); }