bitscale.c revision 7f7f5e4e
123a0898aSmrg/* 223a0898aSmrg 323a0898aSmrgCopyright 1991, 1994, 1998 The Open Group 423a0898aSmrg 523a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its 623a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that 723a0898aSmrgthe above copyright notice appear in all copies and that both that 823a0898aSmrgcopyright notice and this permission notice appear in supporting 923a0898aSmrgdocumentation. 1023a0898aSmrg 1123a0898aSmrgThe above copyright notice and this permission notice shall be included 1223a0898aSmrgin all copies or substantial portions of the Software. 1323a0898aSmrg 1423a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1523a0898aSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1623a0898aSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 1723a0898aSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 1823a0898aSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1923a0898aSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2023a0898aSmrgOTHER DEALINGS IN THE SOFTWARE. 2123a0898aSmrg 2223a0898aSmrgExcept as contained in this notice, the name of The Open Group shall 2323a0898aSmrgnot be used in advertising or otherwise to promote the sale, use or 2423a0898aSmrgother dealings in this Software without prior written authorization 2523a0898aSmrgfrom The Open Group. 2623a0898aSmrg 2723a0898aSmrg*/ 2823a0898aSmrg/* $XFree86: xc/lib/font/bitmap/bitscale.c,v 3.29tsi Exp $ */ 2923a0898aSmrg 3023a0898aSmrg/* 3123a0898aSmrg * Author: Keith Packard, MIT X Consortium 3223a0898aSmrg */ 3323a0898aSmrg 3423a0898aSmrg#ifdef HAVE_CONFIG_H 3523a0898aSmrg#include <config.h> 3623a0898aSmrg#endif 3723a0898aSmrg 3823a0898aSmrg/* 3923a0898aSmrg * Translate monolithic #defines to modular definitions 4023a0898aSmrg */ 4123a0898aSmrg 4223a0898aSmrg#ifdef PCFFORMAT 4323a0898aSmrg#define XFONT_PCFFORMAT 1 4423a0898aSmrg#endif 4523a0898aSmrg 4623a0898aSmrg#ifdef SNFFORMAT 4723a0898aSmrg#define XFONT_SNFFORMAT 1 4823a0898aSmrg#endif 4923a0898aSmrg 5023a0898aSmrg#ifdef BDFFORMAT 5123a0898aSmrg#define XFONT_BDFFORMAT 1 5223a0898aSmrg#endif 5323a0898aSmrg 5423a0898aSmrg#include <X11/fonts/fntfilst.h> 5523a0898aSmrg#include <X11/fonts/bitmap.h> 5623a0898aSmrg#include <X11/fonts/fontutil.h> 5723a0898aSmrg#include <math.h> 5823a0898aSmrg 5923a0898aSmrg#ifndef MAX 6023a0898aSmrg#define MAX(a,b) (((a)>(b)) ? a : b) 6123a0898aSmrg#endif 6223a0898aSmrg 6323a0898aSmrg/* Should get this from elsewhere */ 6423a0898aSmrgextern unsigned long serverGeneration; 6523a0898aSmrg 6623a0898aSmrgstatic void bitmapUnloadScalable (FontPtr pFont); 6723a0898aSmrgstatic void ScaleBitmap ( FontPtr pFont, CharInfoPtr opci, 6823a0898aSmrg CharInfoPtr pci, double *inv_xform, 6923a0898aSmrg double widthMult, double heightMult ); 7023a0898aSmrgstatic FontPtr BitmapScaleBitmaps(FontPtr pf, FontPtr opf, 7123a0898aSmrg double widthMult, double heightMult, 7223a0898aSmrg FontScalablePtr vals); 7323a0898aSmrg 7423a0898aSmrgenum scaleType { 7523a0898aSmrg atom, truncate_atom, pixel_size, point_size, resolution_x, 7623a0898aSmrg resolution_y, average_width, scaledX, scaledY, unscaled, fontname, 7723a0898aSmrg raw_ascent, raw_descent, raw_pixelsize, raw_pointsize, 7823a0898aSmrg raw_average_width, uncomputed 7923a0898aSmrg}; 8023a0898aSmrg 8123a0898aSmrgtypedef struct _fontProp { 8223a0898aSmrg char *name; 8323a0898aSmrg Atom atom; 8423a0898aSmrg enum scaleType type; 8523a0898aSmrg} fontProp; 8623a0898aSmrg 8723a0898aSmrgstatic FontEntryPtr FindBestToScale ( FontPathElementPtr fpe, 8823a0898aSmrg FontEntryPtr entry, 8923a0898aSmrg FontScalablePtr vals, 9023a0898aSmrg FontScalablePtr best, 9123a0898aSmrg double *dxp, double *dyp, 9223a0898aSmrg double *sdxp, double *sdyp, 9323a0898aSmrg FontPathElementPtr *fpep ); 9423a0898aSmrg 9523a0898aSmrgstatic unsigned long bitscaleGeneration = 0; /* initialization flag */ 9623a0898aSmrg 9723a0898aSmrgstatic fontProp fontNamePropTable[] = { 9823a0898aSmrg { "FOUNDRY", 0, atom }, 9923a0898aSmrg { "FAMILY_NAME", 0, atom }, 10023a0898aSmrg { "WEIGHT_NAME", 0, atom }, 10123a0898aSmrg { "SLANT", 0, atom }, 10223a0898aSmrg { "SETWIDTH_NAME", 0, atom }, 10323a0898aSmrg { "ADD_STYLE_NAME", 0, atom }, 10423a0898aSmrg { "PIXEL_SIZE", 0, pixel_size }, 10523a0898aSmrg { "POINT_SIZE", 0, point_size }, 10623a0898aSmrg { "RESOLUTION_X", 0, resolution_x }, 10723a0898aSmrg { "RESOLUTION_Y", 0, resolution_y }, 10823a0898aSmrg { "SPACING", 0, atom }, 10923a0898aSmrg { "AVERAGE_WIDTH", 0, average_width }, 11023a0898aSmrg { "CHARSET_REGISTRY", 0, atom }, 11123a0898aSmrg { "CHARSET_ENCODING", 0, truncate_atom }, 11223a0898aSmrg { "FONT", 0, fontname }, 11323a0898aSmrg { "RAW_ASCENT", 0, raw_ascent }, 11423a0898aSmrg { "RAW_DESCENT", 0, raw_descent }, 11523a0898aSmrg { "RAW_PIXEL_SIZE", 0, raw_pixelsize }, 11623a0898aSmrg { "RAW_POINT_SIZE", 0, raw_pointsize }, 11723a0898aSmrg { "RAW_AVERAGE_WIDTH", 0, raw_average_width } 11823a0898aSmrg}; 11923a0898aSmrg 12023a0898aSmrg#define TRANSFORM_POINT(matrix, x, y, dest) \ 12123a0898aSmrg ((dest)[0] = (matrix)[0] * (x) + (matrix)[2] * (y), \ 12223a0898aSmrg (dest)[1] = (matrix)[1] * (x) + (matrix)[3] * (y)) 12323a0898aSmrg 12423a0898aSmrg#define CHECK_EXTENT(lsb, rsb, desc, asc, data) \ 12523a0898aSmrg ((lsb) > (data)[0] ? (lsb) = (data)[0] : 0 , \ 12623a0898aSmrg (rsb) < (data)[0] ? (rsb) = (data)[0] : 0, \ 12723a0898aSmrg (-desc) > (data)[1] ? (desc) = -(data)[1] : 0 , \ 12823a0898aSmrg (asc) < (data)[1] ? (asc) = (data)[1] : 0) 12923a0898aSmrg 13023a0898aSmrg#define NPROPS (sizeof(fontNamePropTable) / sizeof(fontProp)) 13123a0898aSmrg 13223a0898aSmrg/* Warning: order of the next two tables is critically interdependent. 13323a0898aSmrg Location of "unscaled" properties at the end of fontPropTable[] 13423a0898aSmrg is important. */ 13523a0898aSmrg 13623a0898aSmrgstatic fontProp fontPropTable[] = { 13723a0898aSmrg { "MIN_SPACE", 0, scaledX }, 13823a0898aSmrg { "NORM_SPACE", 0, scaledX }, 13923a0898aSmrg { "MAX_SPACE", 0, scaledX }, 14023a0898aSmrg { "END_SPACE", 0, scaledX }, 14123a0898aSmrg { "AVG_CAPITAL_WIDTH", 0, scaledX }, 14223a0898aSmrg { "AVG_LOWERCASE_WIDTH", 0, scaledX }, 14323a0898aSmrg { "QUAD_WIDTH", 0, scaledX }, 14423a0898aSmrg { "FIGURE_WIDTH", 0, scaledX }, 14523a0898aSmrg { "SUPERSCRIPT_X", 0, scaledX }, 14623a0898aSmrg { "SUPERSCRIPT_Y", 0, scaledY }, 14723a0898aSmrg { "SUBSCRIPT_X", 0, scaledX }, 14823a0898aSmrg { "SUBSCRIPT_Y", 0, scaledY }, 14923a0898aSmrg { "SUPERSCRIPT_SIZE", 0, scaledY }, 15023a0898aSmrg { "SUBSCRIPT_SIZE", 0, scaledY }, 15123a0898aSmrg { "SMALL_CAP_SIZE", 0, scaledY }, 15223a0898aSmrg { "UNDERLINE_POSITION", 0, scaledY }, 15323a0898aSmrg { "UNDERLINE_THICKNESS", 0, scaledY }, 15423a0898aSmrg { "STRIKEOUT_ASCENT", 0, scaledY }, 15523a0898aSmrg { "STRIKEOUT_DESCENT", 0, scaledY }, 15623a0898aSmrg { "CAP_HEIGHT", 0, scaledY }, 15723a0898aSmrg { "X_HEIGHT", 0, scaledY }, 15823a0898aSmrg { "ITALIC_ANGLE", 0, unscaled }, 15923a0898aSmrg { "RELATIVE_SETWIDTH", 0, unscaled }, 16023a0898aSmrg { "RELATIVE_WEIGHT", 0, unscaled }, 16123a0898aSmrg { "WEIGHT", 0, unscaled }, 16223a0898aSmrg { "DESTINATION", 0, unscaled }, 16323a0898aSmrg { "PCL_FONT_NAME", 0, unscaled }, 16423a0898aSmrg { "_ADOBE_POSTSCRIPT_FONTNAME", 0, unscaled } 16523a0898aSmrg}; 16623a0898aSmrg 16723a0898aSmrgstatic fontProp rawFontPropTable[] = { 16823a0898aSmrg { "RAW_MIN_SPACE", 0, }, 16923a0898aSmrg { "RAW_NORM_SPACE", 0, }, 17023a0898aSmrg { "RAW_MAX_SPACE", 0, }, 17123a0898aSmrg { "RAW_END_SPACE", 0, }, 17223a0898aSmrg { "RAW_AVG_CAPITAL_WIDTH", 0, }, 17323a0898aSmrg { "RAW_AVG_LOWERCASE_WIDTH", 0, }, 17423a0898aSmrg { "RAW_QUAD_WIDTH", 0, }, 17523a0898aSmrg { "RAW_FIGURE_WIDTH", 0, }, 17623a0898aSmrg { "RAW_SUPERSCRIPT_X", 0, }, 17723a0898aSmrg { "RAW_SUPERSCRIPT_Y", 0, }, 17823a0898aSmrg { "RAW_SUBSCRIPT_X", 0, }, 17923a0898aSmrg { "RAW_SUBSCRIPT_Y", 0, }, 18023a0898aSmrg { "RAW_SUPERSCRIPT_SIZE", 0, }, 18123a0898aSmrg { "RAW_SUBSCRIPT_SIZE", 0, }, 18223a0898aSmrg { "RAW_SMALL_CAP_SIZE", 0, }, 18323a0898aSmrg { "RAW_UNDERLINE_POSITION", 0, }, 18423a0898aSmrg { "RAW_UNDERLINE_THICKNESS", 0, }, 18523a0898aSmrg { "RAW_STRIKEOUT_ASCENT", 0, }, 18623a0898aSmrg { "RAW_STRIKEOUT_DESCENT", 0, }, 18723a0898aSmrg { "RAW_CAP_HEIGHT", 0, }, 18823a0898aSmrg { "RAW_X_HEIGHT", 0, } 18923a0898aSmrg}; 19023a0898aSmrg 19123a0898aSmrgstatic void 19223a0898aSmrginitFontPropTable(void) 19323a0898aSmrg{ 19423a0898aSmrg int i; 19523a0898aSmrg fontProp *t; 19623a0898aSmrg 19723a0898aSmrg i = sizeof(fontNamePropTable) / sizeof(fontProp); 19823a0898aSmrg for (t = fontNamePropTable; i; i--, t++) 19923a0898aSmrg t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); 20023a0898aSmrg 20123a0898aSmrg i = sizeof(fontPropTable) / sizeof(fontProp); 20223a0898aSmrg for (t = fontPropTable; i; i--, t++) 20323a0898aSmrg t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); 20423a0898aSmrg 20523a0898aSmrg i = sizeof(rawFontPropTable) / sizeof(fontProp); 20623a0898aSmrg for (t = rawFontPropTable; i; i--, t++) 20723a0898aSmrg t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); 20823a0898aSmrg} 20923a0898aSmrg 21023a0898aSmrg#if 0 21123a0898aSmrgstatic FontEntryPtr 21223a0898aSmrgGetScalableEntry (FontPathElementPtr fpe, FontNamePtr name) 21323a0898aSmrg{ 21423a0898aSmrg FontDirectoryPtr dir; 21523a0898aSmrg 21623a0898aSmrg dir = (FontDirectoryPtr) fpe->private; 21723a0898aSmrg return FontFileFindNameInDir (&dir->scalable, name); 21823a0898aSmrg} 21923a0898aSmrg#endif 22023a0898aSmrg 22123a0898aSmrgstatic double 22223a0898aSmrgget_matrix_horizontal_component(double *matrix) 22323a0898aSmrg{ 22423a0898aSmrg return hypot(matrix[0], matrix[1]); 22523a0898aSmrg} 22623a0898aSmrg 22723a0898aSmrgstatic double 22823a0898aSmrgget_matrix_vertical_component(double *matrix) 22923a0898aSmrg{ 23023a0898aSmrg return hypot(matrix[2], matrix[3]); 23123a0898aSmrg} 23223a0898aSmrg 23323a0898aSmrg 23423a0898aSmrgstatic Bool 23523a0898aSmrgComputeScaleFactors(FontScalablePtr from, FontScalablePtr to, 23623a0898aSmrg double *dx, double *dy, double *sdx, double *sdy, 23723a0898aSmrg double *rescale_x) 23823a0898aSmrg{ 23923a0898aSmrg double srcpixelset, destpixelset, srcpixel, destpixel; 24023a0898aSmrg 24123a0898aSmrg srcpixelset = get_matrix_horizontal_component(from->pixel_matrix); 24223a0898aSmrg destpixelset = get_matrix_horizontal_component(to->pixel_matrix); 24323a0898aSmrg srcpixel = get_matrix_vertical_component(from->pixel_matrix); 24423a0898aSmrg destpixel = get_matrix_vertical_component(to->pixel_matrix); 24523a0898aSmrg 24623a0898aSmrg if (srcpixelset >= EPS) 24723a0898aSmrg { 24823a0898aSmrg *dx = destpixelset / srcpixelset; 24923a0898aSmrg *sdx = 1000.0 / srcpixelset; 25023a0898aSmrg } 25123a0898aSmrg else 25223a0898aSmrg *sdx = *dx = 0; 25323a0898aSmrg 25423a0898aSmrg *rescale_x = 1.0; 25523a0898aSmrg 25623a0898aSmrg /* If client specified a width, it overrides setsize; in this 25723a0898aSmrg context, we interpret width as applying to the font before any 25823a0898aSmrg rotation, even though that's not what is ultimately returned in 25923a0898aSmrg the width field. */ 26023a0898aSmrg if (from->width > 0 && to->width > 0 && fabs(*dx) > EPS) 26123a0898aSmrg { 26223a0898aSmrg double rescale = (double)to->width / (double)from->width; 26323a0898aSmrg 26423a0898aSmrg /* If the client specified a transformation matrix, the rescaling 26523a0898aSmrg for width does *not* override the setsize. Instead, just check 26623a0898aSmrg for consistency between the setsize from the matrix and the 26723a0898aSmrg setsize that would result from rescaling according to the width. 26823a0898aSmrg This assumes (perhaps naively) that the width is correctly 26923a0898aSmrg reported in the name. As an interesting side effect, this test 27023a0898aSmrg may result in choosing a different source bitmap (one that 27123a0898aSmrg scales consistently between the setsize *and* the width) than it 27223a0898aSmrg would choose if a width were not specified. Sort of a hidden 27323a0898aSmrg multiple-master functionality. */ 27423a0898aSmrg if ((to->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY || 27523a0898aSmrg (to->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) 27623a0898aSmrg { 27723a0898aSmrg /* Reject if resulting width difference is >= 1 pixel */ 27823a0898aSmrg if (fabs(rescale * from->width - *dx * from->width) >= 10) 27923a0898aSmrg return FALSE; 28023a0898aSmrg } 28123a0898aSmrg else 28223a0898aSmrg { 28323a0898aSmrg *rescale_x = rescale/(*dx); 28423a0898aSmrg *dx = rescale; 28523a0898aSmrg } 28623a0898aSmrg } 28723a0898aSmrg 28823a0898aSmrg if (srcpixel >= EPS) 28923a0898aSmrg { 29023a0898aSmrg *dy = destpixel / srcpixel; 29123a0898aSmrg *sdy = 1000.0 / srcpixel; 29223a0898aSmrg } 29323a0898aSmrg else 29423a0898aSmrg *sdy = *dy = 0; 29523a0898aSmrg 29623a0898aSmrg return TRUE; 29723a0898aSmrg} 29823a0898aSmrg 29923a0898aSmrg/* favor enlargement over reduction because of aliasing resulting 30023a0898aSmrg from reduction */ 30123a0898aSmrg#define SCORE(m,s) \ 30223a0898aSmrgif (m >= 1.0) { \ 30323a0898aSmrg if (m == 1.0) \ 30423a0898aSmrg score += (16 * s); \ 30523a0898aSmrg else if (m == 2.0) \ 30623a0898aSmrg score += (4 * s); \ 30723a0898aSmrg else \ 30823a0898aSmrg score += (int)(((double)(3 * s)) / m); \ 30923a0898aSmrg} else { \ 31023a0898aSmrg score += (int)(((double)(2 * s)) * m); \ 31123a0898aSmrg} 31223a0898aSmrg 31323a0898aSmrg/* don't need to favor enlargement when looking for bitmap that can 31423a0898aSmrg be used unscalable */ 31523a0898aSmrg#define SCORE2(m,s) \ 31623a0898aSmrgif (m >= 1.0) \ 31723a0898aSmrg score += (int)(((double)(8 * s)) / m); \ 31823a0898aSmrgelse \ 31923a0898aSmrg score += (int)(((double)(8 * s)) * m); 32023a0898aSmrg 32123a0898aSmrgstatic FontEntryPtr 32223a0898aSmrgFindBestToScale(FontPathElementPtr fpe, FontEntryPtr entry, 32323a0898aSmrg FontScalablePtr vals, FontScalablePtr best, 32423a0898aSmrg double *dxp, double *dyp, 32523a0898aSmrg double *sdxp, double *sdyp, 32623a0898aSmrg FontPathElementPtr *fpep) 32723a0898aSmrg{ 32823a0898aSmrg FontScalableRec temp; 32923a0898aSmrg int source, i; 33023a0898aSmrg int best_score, best_unscaled_score, 33123a0898aSmrg score; 33223a0898aSmrg double dx = 0.0, sdx = 0.0, dx_amount = 0.0, 33323a0898aSmrg dy = 0.0, sdy = 0.0, dy_amount = 0.0, 33423a0898aSmrg best_dx = 0.0, best_sdx = 0.0, best_dx_amount = 0.0, 33523a0898aSmrg best_dy = 0.0, best_sdy = 0.0, best_dy_amount = 0.0, 33623a0898aSmrg best_unscaled_sdx = 0.0, best_unscaled_sdy = 0.0, 33723a0898aSmrg rescale_x = 0.0, best_rescale_x = 0.0, 33823a0898aSmrg best_unscaled_rescale_x = 0.0; 33923a0898aSmrg FontEntryPtr zero; 34023a0898aSmrg FontNameRec zeroName; 34123a0898aSmrg char zeroChars[MAXFONTNAMELEN]; 34223a0898aSmrg FontDirectoryPtr dir; 34323a0898aSmrg FontScaledPtr scaled; 34423a0898aSmrg FontScalableExtraPtr extra; 34523a0898aSmrg FontScaledPtr best_scaled, best_unscaled; 34623a0898aSmrg FontPathElementPtr best_fpe = NULL, best_unscaled_fpe = NULL; 34723a0898aSmrg FontEntryPtr bitmap = NULL; 34823a0898aSmrg FontEntryPtr result; 34923a0898aSmrg int aliascount = 20; 35023a0898aSmrg FontPathElementPtr bitmap_fpe = NULL; 35123a0898aSmrg FontNameRec xlfdName; 35223a0898aSmrg 35323a0898aSmrg /* find the best match */ 35423a0898aSmrg rescale_x = 1.0; 35523a0898aSmrg best_scaled = 0; 35623a0898aSmrg best_score = 0; 35723a0898aSmrg best_unscaled = 0; 35823a0898aSmrg best_unscaled_score = -1; 35923a0898aSmrg best_dx_amount = best_dy_amount = HUGE_VAL; 36023a0898aSmrg memcpy (zeroChars, entry->name.name, entry->name.length); 36123a0898aSmrg zeroChars[entry->name.length] = '\0'; 36223a0898aSmrg zeroName.name = zeroChars; 36323a0898aSmrg FontParseXLFDName (zeroChars, &temp, FONT_XLFD_REPLACE_ZERO); 36423a0898aSmrg zeroName.length = strlen (zeroChars); 36523a0898aSmrg zeroName.ndashes = entry->name.ndashes; 36623a0898aSmrg xlfdName.name = vals->xlfdName; 36723a0898aSmrg xlfdName.length = strlen(xlfdName.name); 36823a0898aSmrg xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length); 36923a0898aSmrg restart_bestscale_loop: ; 37023a0898aSmrg /* 37123a0898aSmrg * Look through all the registered bitmap sources for 37223a0898aSmrg * the same zero name as ours; entries along that one 37323a0898aSmrg * can be scaled as desired. 37423a0898aSmrg */ 37523a0898aSmrg for (source = 0; source < FontFileBitmapSources.count; source++) 37623a0898aSmrg { 37723a0898aSmrg /* There might already be a bitmap that satisfies the request 37823a0898aSmrg but didn't have a zero name that was found by the scalable 37923a0898aSmrg font matching logic. Keep track if there is. */ 38023a0898aSmrg if (bitmap == NULL && vals->xlfdName != NULL) 38123a0898aSmrg { 38223a0898aSmrg bitmap_fpe = FontFileBitmapSources.fpe[source]; 38323a0898aSmrg dir = (FontDirectoryPtr) bitmap_fpe->private; 38423a0898aSmrg bitmap = FontFileFindNameInDir (&dir->nonScalable, &xlfdName); 38523a0898aSmrg if (bitmap && bitmap->type != FONT_ENTRY_BITMAP) 38623a0898aSmrg { 38723a0898aSmrg if (bitmap->type == FONT_ENTRY_ALIAS && aliascount > 0) 38823a0898aSmrg { 38923a0898aSmrg aliascount--; 39023a0898aSmrg xlfdName.name = bitmap->u.alias.resolved; 39123a0898aSmrg xlfdName.length = strlen(xlfdName.name); 39223a0898aSmrg xlfdName.ndashes = FontFileCountDashes(xlfdName.name, 39323a0898aSmrg xlfdName.length); 39423a0898aSmrg bitmap = NULL; 39523a0898aSmrg goto restart_bestscale_loop; 39623a0898aSmrg } 39723a0898aSmrg else 39823a0898aSmrg bitmap = NULL; 39923a0898aSmrg } 40023a0898aSmrg } 40123a0898aSmrg 40223a0898aSmrg if (FontFileBitmapSources.fpe[source] == fpe) 40323a0898aSmrg zero = entry; 40423a0898aSmrg else 40523a0898aSmrg { 40623a0898aSmrg dir = (FontDirectoryPtr) FontFileBitmapSources.fpe[source]->private; 40723a0898aSmrg zero = FontFileFindNameInDir (&dir->scalable, &zeroName); 40823a0898aSmrg if (!zero) 40923a0898aSmrg continue; 41023a0898aSmrg } 41123a0898aSmrg extra = zero->u.scalable.extra; 41223a0898aSmrg for (i = 0; i < extra->numScaled; i++) 41323a0898aSmrg { 41423a0898aSmrg scaled = &extra->scaled[i]; 41523a0898aSmrg if (!scaled->bitmap) 41623a0898aSmrg continue; 41723a0898aSmrg if (!ComputeScaleFactors(&scaled->vals, vals, &dx, &dy, &sdx, &sdy, 41823a0898aSmrg &rescale_x)) 41923a0898aSmrg continue; 42023a0898aSmrg score = 0; 42123a0898aSmrg dx_amount = dx; 42223a0898aSmrg dy_amount = dy; 42323a0898aSmrg SCORE(dy_amount, 10); 42423a0898aSmrg SCORE(dx_amount, 1); 42523a0898aSmrg if ((score > best_score) || 42623a0898aSmrg ((score == best_score) && 42723a0898aSmrg ((dy_amount < best_dy_amount) || 42823a0898aSmrg ((dy_amount == best_dy_amount) && 42923a0898aSmrg (dx_amount < best_dx_amount))))) 43023a0898aSmrg { 43123a0898aSmrg best_fpe = FontFileBitmapSources.fpe[source]; 43223a0898aSmrg best_scaled = scaled; 43323a0898aSmrg best_score = score; 43423a0898aSmrg best_dx = dx; 43523a0898aSmrg best_dy = dy; 43623a0898aSmrg best_sdx = sdx; 43723a0898aSmrg best_sdy = sdy; 43823a0898aSmrg best_dx_amount = dx_amount; 43923a0898aSmrg best_dy_amount = dy_amount; 44023a0898aSmrg best_rescale_x = rescale_x; 44123a0898aSmrg } 44223a0898aSmrg /* Is this font a candidate for use without ugly rescaling? */ 44323a0898aSmrg if (fabs(dx) > EPS && fabs(dy) > EPS && 44423a0898aSmrg fabs(vals->pixel_matrix[0] * rescale_x - 44523a0898aSmrg scaled->vals.pixel_matrix[0]) < 1 && 44623a0898aSmrg fabs(vals->pixel_matrix[1] * rescale_x - 44723a0898aSmrg scaled->vals.pixel_matrix[1]) < EPS && 44823a0898aSmrg fabs(vals->pixel_matrix[2] - 44923a0898aSmrg scaled->vals.pixel_matrix[2]) < EPS && 45023a0898aSmrg fabs(vals->pixel_matrix[3] - 45123a0898aSmrg scaled->vals.pixel_matrix[3]) < 1) 45223a0898aSmrg { 45323a0898aSmrg /* Yes. The pixel sizes are close on the diagonal and 45423a0898aSmrg extremely close off the diagonal. */ 45523a0898aSmrg score = 0; 45623a0898aSmrg SCORE2(vals->pixel_matrix[3] / 45723a0898aSmrg scaled->vals.pixel_matrix[3], 10); 45823a0898aSmrg SCORE2(vals->pixel_matrix[0] * rescale_x / 45923a0898aSmrg scaled->vals.pixel_matrix[0], 1); 46023a0898aSmrg if (score > best_unscaled_score) 46123a0898aSmrg { 46223a0898aSmrg best_unscaled_fpe = FontFileBitmapSources.fpe[source]; 46323a0898aSmrg best_unscaled = scaled; 46423a0898aSmrg best_unscaled_sdx = sdx / dx; 46523a0898aSmrg best_unscaled_sdy = sdy / dy; 46623a0898aSmrg best_unscaled_score = score; 46723a0898aSmrg best_unscaled_rescale_x = rescale_x; 46823a0898aSmrg } 46923a0898aSmrg } 47023a0898aSmrg } 47123a0898aSmrg } 47223a0898aSmrg if (best_unscaled) 47323a0898aSmrg { 47423a0898aSmrg *best = best_unscaled->vals; 47523a0898aSmrg *fpep = best_unscaled_fpe; 47623a0898aSmrg *dxp = 1.0; 47723a0898aSmrg *dyp = 1.0; 47823a0898aSmrg *sdxp = best_unscaled_sdx; 47923a0898aSmrg *sdyp = best_unscaled_sdy; 48023a0898aSmrg rescale_x = best_unscaled_rescale_x; 48123a0898aSmrg result = best_unscaled->bitmap; 48223a0898aSmrg } 48323a0898aSmrg else if (best_scaled) 48423a0898aSmrg { 48523a0898aSmrg *best = best_scaled->vals; 48623a0898aSmrg *fpep = best_fpe; 48723a0898aSmrg *dxp = best_dx; 48823a0898aSmrg *dyp = best_dy; 48923a0898aSmrg *sdxp = best_sdx; 49023a0898aSmrg *sdyp = best_sdy; 49123a0898aSmrg rescale_x = best_rescale_x; 49223a0898aSmrg result = best_scaled->bitmap; 49323a0898aSmrg } 49423a0898aSmrg else 49523a0898aSmrg result = NULL; 49623a0898aSmrg 49723a0898aSmrg if (bitmap != NULL && (result == NULL || *dxp != 1.0 || *dyp != 1.0)) 49823a0898aSmrg { 49923a0898aSmrg *fpep = bitmap_fpe; 50023a0898aSmrg FontParseXLFDName (bitmap->name.name, best, FONT_XLFD_REPLACE_NONE); 50123a0898aSmrg if (ComputeScaleFactors(best, best, dxp, dyp, sdxp, sdyp, &rescale_x)) 50223a0898aSmrg result = bitmap; 50323a0898aSmrg else 50423a0898aSmrg result = NULL; 50523a0898aSmrg } 50623a0898aSmrg 50723a0898aSmrg if (result && rescale_x != 1.0) 50823a0898aSmrg { 50923a0898aSmrg /* We have rescaled horizontally due to an XLFD width field. Change 51023a0898aSmrg the matrix appropriately */ 51123a0898aSmrg vals->pixel_matrix[0] *= rescale_x; 51223a0898aSmrg vals->pixel_matrix[1] *= rescale_x; 51323a0898aSmrg vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK; 51423a0898aSmrg /* Recompute and reround the FontScalablePtr values after 51523a0898aSmrg rescaling for the new width. */ 51623a0898aSmrg FontFileCompleteXLFD(vals, vals); 51723a0898aSmrg } 51823a0898aSmrg 51923a0898aSmrg return result; 52023a0898aSmrg} 52123a0898aSmrg 52223a0898aSmrgstatic long 52323a0898aSmrgdoround(double x) 52423a0898aSmrg{ 52523a0898aSmrg return (x >= 0) ? (long)(x + .5) : (long)(x - .5); 52623a0898aSmrg} 52723a0898aSmrg 52823a0898aSmrgstatic int 52923a0898aSmrgcomputeProps(FontPropPtr pf, char *wasStringProp, 53023a0898aSmrg FontPropPtr npf, char *isStringProp, 53123a0898aSmrg unsigned int nprops, double xfactor, double yfactor, 53223a0898aSmrg double sXfactor, double sYfactor) 53323a0898aSmrg{ 53423a0898aSmrg int n; 53523a0898aSmrg int count; 53623a0898aSmrg fontProp *t; 53723a0898aSmrg double rawfactor = 0.0; 53823a0898aSmrg 53923a0898aSmrg for (count = 0; nprops > 0; nprops--, pf++, wasStringProp++) { 54023a0898aSmrg n = sizeof(fontPropTable) / sizeof(fontProp); 54123a0898aSmrg for (t = fontPropTable; n && (t->atom != pf->name); n--, t++); 54223a0898aSmrg if (!n) 54323a0898aSmrg continue; 54423a0898aSmrg 54523a0898aSmrg switch (t->type) { 54623a0898aSmrg case scaledX: 54723a0898aSmrg npf->value = doround(xfactor * (double)pf->value); 54823a0898aSmrg rawfactor = sXfactor; 54923a0898aSmrg break; 55023a0898aSmrg case scaledY: 55123a0898aSmrg npf->value = doround(yfactor * (double)pf->value); 55223a0898aSmrg rawfactor = sYfactor; 55323a0898aSmrg break; 55423a0898aSmrg case unscaled: 55523a0898aSmrg npf->value = pf->value; 55623a0898aSmrg npf->name = pf->name; 55723a0898aSmrg npf++; 55823a0898aSmrg count++; 55923a0898aSmrg *isStringProp++ = *wasStringProp; 56023a0898aSmrg break; 56123a0898aSmrg default: 56223a0898aSmrg break; 56323a0898aSmrg } 56423a0898aSmrg if (t->type != unscaled) 56523a0898aSmrg { 56623a0898aSmrg npf->name = pf->name; 56723a0898aSmrg npf++; 56823a0898aSmrg count++; 56923a0898aSmrg npf->value = doround(rawfactor * (double)pf->value); 57023a0898aSmrg npf->name = rawFontPropTable[t - fontPropTable].atom; 57123a0898aSmrg npf++; 57223a0898aSmrg count++; 57323a0898aSmrg *isStringProp++ = *wasStringProp; 57423a0898aSmrg *isStringProp++ = *wasStringProp; 57523a0898aSmrg } 57623a0898aSmrg } 57723a0898aSmrg return count; 57823a0898aSmrg} 57923a0898aSmrg 58023a0898aSmrg 58123a0898aSmrgstatic int 58223a0898aSmrgComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the font to be scaled */ 58323a0898aSmrg char *name, /* name of resulting font */ 58423a0898aSmrg FontScalablePtr vals, 58523a0898aSmrg double dx, double dy, /* scale factors in x and y */ 58623a0898aSmrg double sdx, double sdy, /* directions */ 58723a0898aSmrg long sWidth, /* 1000-pixel average width */ 58823a0898aSmrg FontPropPtr *pProps, /* returns properties; 58923a0898aSmrg preallocated */ 59023a0898aSmrg char **pIsStringProp) /* return booleans; 59123a0898aSmrg preallocated */ 59223a0898aSmrg{ 59323a0898aSmrg int n; 59423a0898aSmrg char *ptr1 = NULL, *ptr2 = NULL; 59523a0898aSmrg char *ptr3; 59623a0898aSmrg FontPropPtr fp; 59723a0898aSmrg fontProp *fpt; 59823a0898aSmrg char *isStringProp; 59923a0898aSmrg int nProps; 60023a0898aSmrg 60123a0898aSmrg if (bitscaleGeneration != serverGeneration) { 60223a0898aSmrg initFontPropTable(); 60323a0898aSmrg bitscaleGeneration = serverGeneration; 60423a0898aSmrg } 60523a0898aSmrg nProps = NPROPS + 1 + sizeof(fontPropTable) / sizeof(fontProp) + 60623a0898aSmrg sizeof(rawFontPropTable) / sizeof(fontProp); 6077f7f5e4eSmrg fp = malloc(sizeof(FontPropRec) * nProps); 60823a0898aSmrg *pProps = fp; 60923a0898aSmrg if (!fp) { 61023a0898aSmrg fprintf(stderr, "Error: Couldn't allocate font properties (%ld*%d)\n", 61123a0898aSmrg (unsigned long)sizeof(FontPropRec), nProps); 61223a0898aSmrg return 1; 61323a0898aSmrg } 6147f7f5e4eSmrg isStringProp = malloc (nProps); 61523a0898aSmrg *pIsStringProp = isStringProp; 61623a0898aSmrg if (!isStringProp) 61723a0898aSmrg { 61823a0898aSmrg fprintf(stderr, "Error: Couldn't allocate isStringProp (%d)\n", nProps); 6197f7f5e4eSmrg free (fp); 62023a0898aSmrg return 1; 62123a0898aSmrg } 62223a0898aSmrg ptr2 = name; 62323a0898aSmrg for (fpt = fontNamePropTable, n = NPROPS; 62423a0898aSmrg n; 62523a0898aSmrg fp++, fpt++, n--, isStringProp++) 62623a0898aSmrg { 62723a0898aSmrg 62823a0898aSmrg if (*ptr2) 62923a0898aSmrg { 63023a0898aSmrg ptr1 = ptr2 + 1; 63123a0898aSmrg if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0'); 63223a0898aSmrg } 63323a0898aSmrg 63423a0898aSmrg *isStringProp = 0; 63523a0898aSmrg switch (fpt->type) { 63623a0898aSmrg case atom: 63723a0898aSmrg fp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE); 63823a0898aSmrg *isStringProp = 1; 63923a0898aSmrg break; 64023a0898aSmrg case truncate_atom: 64123a0898aSmrg for (ptr3 = ptr1; *ptr3; ptr3++) 64223a0898aSmrg if (*ptr3 == '[') 64323a0898aSmrg break; 64423a0898aSmrg if (!*ptr3) ptr3 = ptr2; 64523a0898aSmrg fp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE); 64623a0898aSmrg *isStringProp = 1; 64723a0898aSmrg break; 64823a0898aSmrg case pixel_size: 64923a0898aSmrg fp->value = doround(vals->pixel_matrix[3]); 65023a0898aSmrg break; 65123a0898aSmrg case point_size: 65223a0898aSmrg fp->value = doround(vals->point_matrix[3] * 10.0); 65323a0898aSmrg break; 65423a0898aSmrg case resolution_x: 65523a0898aSmrg fp->value = vals->x; 65623a0898aSmrg break; 65723a0898aSmrg case resolution_y: 65823a0898aSmrg fp->value = vals->y; 65923a0898aSmrg break; 66023a0898aSmrg case average_width: 66123a0898aSmrg fp->value = vals->width; 66223a0898aSmrg break; 66323a0898aSmrg case fontname: 66423a0898aSmrg fp->value = MakeAtom(name, strlen(name), TRUE); 66523a0898aSmrg *isStringProp = 1; 66623a0898aSmrg break; 66723a0898aSmrg case raw_ascent: 66823a0898aSmrg fp->value = sourceFontInfo->fontAscent * sdy; 66923a0898aSmrg break; 67023a0898aSmrg case raw_descent: 67123a0898aSmrg fp->value = sourceFontInfo->fontDescent * sdy; 67223a0898aSmrg break; 67323a0898aSmrg case raw_pointsize: 67423a0898aSmrg fp->value = (long)(72270.0 / (double)vals->y + .5); 67523a0898aSmrg break; 67623a0898aSmrg case raw_pixelsize: 67723a0898aSmrg fp->value = 1000; 67823a0898aSmrg break; 67923a0898aSmrg case raw_average_width: 68023a0898aSmrg fp->value = sWidth; 68123a0898aSmrg break; 68223a0898aSmrg default: 68323a0898aSmrg break; 68423a0898aSmrg } 68523a0898aSmrg fp->name = fpt->atom; 68623a0898aSmrg } 68723a0898aSmrg n = NPROPS; 68823a0898aSmrg n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp, 68923a0898aSmrg fp, isStringProp, sourceFontInfo->nprops, dx, dy, 69023a0898aSmrg sdx, sdy); 69123a0898aSmrg return n; 69223a0898aSmrg} 69323a0898aSmrg 69423a0898aSmrg 69523a0898aSmrgstatic int 69623a0898aSmrgcompute_xform_matrix(FontScalablePtr vals, double dx, double dy, 69723a0898aSmrg double *xform, double *inv_xform, 69823a0898aSmrg double *xmult, double *ymult) 69923a0898aSmrg{ 70023a0898aSmrg double det; 70123a0898aSmrg double pixel = get_matrix_vertical_component(vals->pixel_matrix); 70223a0898aSmrg double pixelset = get_matrix_horizontal_component(vals->pixel_matrix); 70323a0898aSmrg 70423a0898aSmrg if (pixel < EPS || pixelset < EPS) return 0; 70523a0898aSmrg 70623a0898aSmrg /* Initialize the transformation matrix to the scaling factors */ 70723a0898aSmrg xform[0] = dx / pixelset; 70823a0898aSmrg xform[1] = xform[2] = 0.0; 70923a0898aSmrg xform[3] = dy / pixel; 71023a0898aSmrg 71123a0898aSmrg/* Inline matrix multiply -- somewhat ugly to minimize register usage */ 71223a0898aSmrg#define MULTIPLY_XFORM(a,b,c,d) \ 71323a0898aSmrg{ \ 71423a0898aSmrg register double aa = (a), bb = (b), cc = (c), dd = (d); \ 71523a0898aSmrg register double temp; \ 71623a0898aSmrg temp = aa * xform[0] + cc * xform[1]; \ 71723a0898aSmrg aa = aa * xform[2] + cc * xform[3]; \ 71823a0898aSmrg xform[1] = bb * xform[0] + dd * xform[1]; \ 71923a0898aSmrg xform[3] = bb * xform[2] + dd * xform[3]; \ 72023a0898aSmrg xform[0] = temp; \ 72123a0898aSmrg xform[2] = aa; \ 72223a0898aSmrg} 72323a0898aSmrg 72423a0898aSmrg /* Rescale the transformation matrix for size of source font */ 72523a0898aSmrg MULTIPLY_XFORM(vals->pixel_matrix[0], 72623a0898aSmrg vals->pixel_matrix[1], 72723a0898aSmrg vals->pixel_matrix[2], 72823a0898aSmrg vals->pixel_matrix[3]); 72923a0898aSmrg 73023a0898aSmrg *xmult = xform[0]; 73123a0898aSmrg *ymult = xform[3]; 73223a0898aSmrg 73323a0898aSmrg 73423a0898aSmrg if (inv_xform == NULL) return 1; 73523a0898aSmrg 73623a0898aSmrg /* Compute the determinant for use in inverting the matrix. */ 73723a0898aSmrg det = xform[0] * xform[3] - xform[1] * xform[2]; 73823a0898aSmrg 73923a0898aSmrg /* If the determinant is tiny or zero, give up */ 74023a0898aSmrg if (fabs(det) < EPS) return 0; 74123a0898aSmrg 74223a0898aSmrg /* Compute the inverse */ 74323a0898aSmrg inv_xform[0] = xform[3] / det; 74423a0898aSmrg inv_xform[1] = -xform[1] / det; 74523a0898aSmrg inv_xform[2] = -xform[2] / det; 74623a0898aSmrg inv_xform[3] = xform[0] / det; 74723a0898aSmrg 74823a0898aSmrg return 1; 74923a0898aSmrg} 75023a0898aSmrg 75123a0898aSmrg/* 75223a0898aSmrg * ScaleFont 75323a0898aSmrg * returns a pointer to the new scaled font, or NULL (due to AllocError). 75423a0898aSmrg */ 75523a0898aSmrgstatic FontPtr 75623a0898aSmrgScaleFont(FontPtr opf, /* originating font */ 75723a0898aSmrg double widthMult, /* glyphs width scale factor */ 75823a0898aSmrg double heightMult, /* glyphs height scale factor */ 75923a0898aSmrg double sWidthMult, /* scalable glyphs width scale factor */ 76023a0898aSmrg double sHeightMult, /* scalable glyphs height scale factor */ 76123a0898aSmrg FontScalablePtr vals, 76223a0898aSmrg double *newWidthMult, /* return: X component of glyphs width 76323a0898aSmrg scale factor */ 76423a0898aSmrg double *newHeightMult, /* return: Y component of glyphs height 76523a0898aSmrg scale factor */ 76623a0898aSmrg long *sWidth) /* return: average 1000-pixel width */ 76723a0898aSmrg{ 76823a0898aSmrg FontPtr pf; 76923a0898aSmrg FontInfoPtr pfi, 77023a0898aSmrg opfi; 77123a0898aSmrg BitmapFontPtr bitmapFont, 77223a0898aSmrg obitmapFont; 77323a0898aSmrg CharInfoPtr pci, 77423a0898aSmrg opci; 77523a0898aSmrg int nchars = 0; /* how many characters in the font */ 77623a0898aSmrg int i; 77723a0898aSmrg int firstCol, lastCol, firstRow, lastRow; 77823a0898aSmrg double xform[4], inv_xform[4]; 77923a0898aSmrg double xmult, ymult; 78023a0898aSmrg int totalwidth = 0, totalchars = 0; 78123a0898aSmrg#define OLDINDEX(i) (((i)/(lastCol - firstCol + 1) + \ 78223a0898aSmrg firstRow - opf->info.firstRow) * \ 78323a0898aSmrg (opf->info.lastCol - opf->info.firstCol + 1) + \ 78423a0898aSmrg (i)%(lastCol - firstCol + 1) + \ 78523a0898aSmrg firstCol - opf->info.firstCol) 78623a0898aSmrg 78723a0898aSmrg *sWidth = 0; 78823a0898aSmrg 78923a0898aSmrg opfi = &opf->info; 79023a0898aSmrg obitmapFont = (BitmapFontPtr) opf->fontPrivate; 79123a0898aSmrg 79223a0898aSmrg bitmapFont = 0; 79323a0898aSmrg if (!(pf = CreateFontRec())) { 79423a0898aSmrg fprintf(stderr, "Error: Couldn't allocate FontRec (%ld)\n", 79523a0898aSmrg (unsigned long)sizeof(FontRec)); 79623a0898aSmrg goto bail; 79723a0898aSmrg } 79823a0898aSmrg pf->refcnt = 0; 79923a0898aSmrg pf->bit = opf->bit; 80023a0898aSmrg pf->byte = opf->byte; 80123a0898aSmrg pf->glyph = opf->glyph; 80223a0898aSmrg pf->scan = opf->scan; 80323a0898aSmrg 80423a0898aSmrg pf->get_glyphs = bitmapGetGlyphs; 80523a0898aSmrg pf->get_metrics = bitmapGetMetrics; 80623a0898aSmrg pf->unload_font = bitmapUnloadScalable; 80723a0898aSmrg pf->unload_glyphs = NULL; 80823a0898aSmrg 80923a0898aSmrg pfi = &pf->info; 81023a0898aSmrg *pfi = *opfi; 81123a0898aSmrg /* If charset subsetting specified in vals, determine what our range 81223a0898aSmrg needs to be for the output font */ 81323a0898aSmrg if (vals->nranges) 81423a0898aSmrg { 81523a0898aSmrg int i; 81623a0898aSmrg 81723a0898aSmrg pfi->allExist = 0; 81823a0898aSmrg firstCol = 255; 81923a0898aSmrg lastCol = 0; 82023a0898aSmrg firstRow = 255; 82123a0898aSmrg lastRow = 0; 82223a0898aSmrg 82323a0898aSmrg for (i = 0; i < vals->nranges; i++) 82423a0898aSmrg { 82523a0898aSmrg if (vals->ranges[i].min_char_high != vals->ranges[i].max_char_high) 82623a0898aSmrg { 82723a0898aSmrg firstCol = opfi->firstCol; 82823a0898aSmrg lastCol = opfi->lastCol; 82923a0898aSmrg } 83023a0898aSmrg if (firstCol > vals->ranges[i].min_char_low) 83123a0898aSmrg firstCol = vals->ranges[i].min_char_low; 83223a0898aSmrg if (lastCol < vals->ranges[i].max_char_low) 83323a0898aSmrg lastCol = vals->ranges[i].max_char_low; 83423a0898aSmrg if (firstRow > vals->ranges[i].min_char_high) 83523a0898aSmrg firstRow = vals->ranges[i].min_char_high; 83623a0898aSmrg if (lastRow < vals->ranges[i].max_char_high) 83723a0898aSmrg lastRow = vals->ranges[i].max_char_high; 83823a0898aSmrg } 83923a0898aSmrg 84023a0898aSmrg if (firstCol > lastCol || firstRow > lastRow) 84123a0898aSmrg goto bail; 84223a0898aSmrg 84323a0898aSmrg if (firstCol < opfi->firstCol) 84423a0898aSmrg firstCol = opfi->firstCol; 84523a0898aSmrg if (lastCol > opfi->lastCol) 84623a0898aSmrg lastCol = opfi->lastCol; 84723a0898aSmrg if (firstRow < opfi->firstRow) 84823a0898aSmrg firstRow = opfi->firstRow; 84923a0898aSmrg if (lastRow > opfi->lastRow) 85023a0898aSmrg lastRow = opfi->lastRow; 85123a0898aSmrg } 85223a0898aSmrg else 85323a0898aSmrg { 85423a0898aSmrg firstCol = opfi->firstCol; 85523a0898aSmrg lastCol = opfi->lastCol; 85623a0898aSmrg firstRow = opfi->firstRow; 85723a0898aSmrg lastRow = opfi->lastRow; 85823a0898aSmrg } 85923a0898aSmrg 8607f7f5e4eSmrg bitmapFont = malloc(sizeof(BitmapFontRec)); 86123a0898aSmrg if (!bitmapFont) { 86223a0898aSmrg fprintf(stderr, "Error: Couldn't allocate bitmapFont (%ld)\n", 86323a0898aSmrg (unsigned long)sizeof(BitmapFontRec)); 86423a0898aSmrg goto bail; 86523a0898aSmrg } 86623a0898aSmrg nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); 86723a0898aSmrg pfi->firstRow = firstRow; 86823a0898aSmrg pfi->lastRow = lastRow; 86923a0898aSmrg pfi->firstCol = firstCol; 87023a0898aSmrg pfi->lastCol = lastCol; 87123a0898aSmrg pf->fontPrivate = (pointer) bitmapFont; 87223a0898aSmrg bitmapFont->version_num = obitmapFont->version_num; 87323a0898aSmrg bitmapFont->num_chars = nchars; 87423a0898aSmrg bitmapFont->num_tables = obitmapFont->num_tables; 87523a0898aSmrg bitmapFont->metrics = 0; 87623a0898aSmrg bitmapFont->ink_metrics = 0; 87723a0898aSmrg bitmapFont->bitmaps = 0; 87823a0898aSmrg bitmapFont->encoding = 0; 87923a0898aSmrg bitmapFont->bitmapExtra = 0; 88023a0898aSmrg bitmapFont->pDefault = 0; 8817f7f5e4eSmrg bitmapFont->metrics = malloc(nchars * sizeof(CharInfoRec)); 88223a0898aSmrg if (!bitmapFont->metrics) { 88323a0898aSmrg fprintf(stderr, "Error: Couldn't allocate metrics (%d*%ld)\n", 88423a0898aSmrg nchars, (unsigned long)sizeof(CharInfoRec)); 88523a0898aSmrg goto bail; 88623a0898aSmrg } 8877f7f5e4eSmrg bitmapFont->encoding = calloc(NUM_SEGMENTS(nchars), sizeof(CharInfoPtr*)); 88823a0898aSmrg if (!bitmapFont->encoding) { 88923a0898aSmrg fprintf(stderr, "Error: Couldn't allocate encoding (%d*%ld)\n", 89023a0898aSmrg nchars, (unsigned long)sizeof(CharInfoPtr)); 89123a0898aSmrg goto bail; 89223a0898aSmrg } 89323a0898aSmrg 89423a0898aSmrg#undef MAXSHORT 89523a0898aSmrg#define MAXSHORT 32767 89623a0898aSmrg#undef MINSHORT 89723a0898aSmrg#define MINSHORT -32768 89823a0898aSmrg 89923a0898aSmrg pfi->anamorphic = FALSE; 90023a0898aSmrg if (heightMult != widthMult) 90123a0898aSmrg pfi->anamorphic = TRUE; 90223a0898aSmrg pfi->cachable = TRUE; 90323a0898aSmrg 90423a0898aSmrg if (!compute_xform_matrix(vals, widthMult, heightMult, xform, 90523a0898aSmrg inv_xform, &xmult, &ymult)) 90623a0898aSmrg goto bail; 90723a0898aSmrg 90823a0898aSmrg pfi->fontAscent = opfi->fontAscent * ymult; 90923a0898aSmrg pfi->fontDescent = opfi->fontDescent * ymult; 91023a0898aSmrg 91123a0898aSmrg pfi->minbounds.leftSideBearing = MAXSHORT; 91223a0898aSmrg pfi->minbounds.rightSideBearing = MAXSHORT; 91323a0898aSmrg pfi->minbounds.ascent = MAXSHORT; 91423a0898aSmrg pfi->minbounds.descent = MAXSHORT; 91523a0898aSmrg pfi->minbounds.characterWidth = MAXSHORT; 91623a0898aSmrg pfi->minbounds.attributes = MAXSHORT; 91723a0898aSmrg 91823a0898aSmrg pfi->maxbounds.leftSideBearing = MINSHORT; 91923a0898aSmrg pfi->maxbounds.rightSideBearing = MINSHORT; 92023a0898aSmrg pfi->maxbounds.ascent = MINSHORT; 92123a0898aSmrg pfi->maxbounds.descent = MINSHORT; 92223a0898aSmrg pfi->maxbounds.characterWidth = MINSHORT; 92323a0898aSmrg pfi->maxbounds.attributes = MINSHORT; 92423a0898aSmrg 92523a0898aSmrg /* Compute the transformation and inverse transformation matrices. 92623a0898aSmrg Can fail if the determinant is zero. */ 92723a0898aSmrg 92823a0898aSmrg pci = bitmapFont->metrics; 92923a0898aSmrg for (i = 0; i < nchars; i++) 93023a0898aSmrg { 93123a0898aSmrg if ((opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i)))) 93223a0898aSmrg { 93323a0898aSmrg double newlsb, newrsb, newdesc, newasc, point[2]; 93423a0898aSmrg 93523a0898aSmrg#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8)) 93623a0898aSmrg#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8)) 93723a0898aSmrg 93823a0898aSmrg if (vals->nranges) 93923a0898aSmrg { 94023a0898aSmrg int row = i / (lastCol - firstCol + 1) + firstRow; 94123a0898aSmrg int col = i % (lastCol - firstCol + 1) + firstCol; 94223a0898aSmrg int ch = (row << 8) + col; 94323a0898aSmrg int j; 94423a0898aSmrg for (j = 0; j < vals->nranges; j++) 94523a0898aSmrg if (ch >= minchar(vals->ranges[j]) && 94623a0898aSmrg ch <= maxchar(vals->ranges[j])) 94723a0898aSmrg break; 94823a0898aSmrg if (j == vals->nranges) 94923a0898aSmrg { 95023a0898aSmrg continue; 95123a0898aSmrg } 95223a0898aSmrg } 95323a0898aSmrg 95423a0898aSmrg if (opci->metrics.leftSideBearing == 0 && 95523a0898aSmrg opci->metrics.rightSideBearing == 0 && 95623a0898aSmrg opci->metrics.ascent == 0 && 95723a0898aSmrg opci->metrics.descent == 0 && 95823a0898aSmrg opci->metrics.characterWidth == 0) 95923a0898aSmrg { 96023a0898aSmrg continue; 96123a0898aSmrg } 96223a0898aSmrg 96323a0898aSmrg if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) { 96423a0898aSmrg bitmapFont->encoding[SEGMENT_MAJOR(i)]= 9657f7f5e4eSmrg calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr)); 96623a0898aSmrg if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) 96723a0898aSmrg goto bail; 96823a0898aSmrg } 96923a0898aSmrg ACCESSENCODINGL(bitmapFont->encoding, i) = pci; 97023a0898aSmrg 97123a0898aSmrg /* Compute new extents for this glyph */ 97223a0898aSmrg TRANSFORM_POINT(xform, 97323a0898aSmrg opci->metrics.leftSideBearing, 97423a0898aSmrg -opci->metrics.descent, 97523a0898aSmrg point); 97623a0898aSmrg newlsb = point[0]; 97723a0898aSmrg newrsb = newlsb; 97823a0898aSmrg newdesc = -point[1]; 97923a0898aSmrg newasc = -newdesc; 98023a0898aSmrg TRANSFORM_POINT(xform, 98123a0898aSmrg opci->metrics.leftSideBearing, 98223a0898aSmrg opci->metrics.ascent, 98323a0898aSmrg point); 98423a0898aSmrg CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); 98523a0898aSmrg TRANSFORM_POINT(xform, 98623a0898aSmrg opci->metrics.rightSideBearing, 98723a0898aSmrg -opci->metrics.descent, 98823a0898aSmrg point); 98923a0898aSmrg CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); 99023a0898aSmrg TRANSFORM_POINT(xform, 99123a0898aSmrg opci->metrics.rightSideBearing, 99223a0898aSmrg opci->metrics.ascent, 99323a0898aSmrg point); 99423a0898aSmrg CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); 99523a0898aSmrg 99623a0898aSmrg pci->metrics.leftSideBearing = (int)floor(newlsb); 99723a0898aSmrg pci->metrics.rightSideBearing = (int)floor(newrsb + .5); 99823a0898aSmrg pci->metrics.descent = (int)ceil(newdesc); 99923a0898aSmrg pci->metrics.ascent = (int)floor(newasc + .5); 100023a0898aSmrg /* Accumulate total width of characters before transformation, 100123a0898aSmrg to ascertain predominant direction of font. */ 100223a0898aSmrg totalwidth += opci->metrics.characterWidth; 100323a0898aSmrg pci->metrics.characterWidth = 100423a0898aSmrg doround((double)opci->metrics.characterWidth * xmult); 100523a0898aSmrg pci->metrics.attributes = 100623a0898aSmrg doround((double)opci->metrics.characterWidth * sWidthMult); 100723a0898aSmrg if (!pci->metrics.characterWidth) 100823a0898aSmrg { 100923a0898aSmrg /* Since transformation may shrink width, height, and 101023a0898aSmrg escapement to zero, make sure existing characters 101123a0898aSmrg are not mistaken for undefined characters. */ 101223a0898aSmrg 101323a0898aSmrg if (pci->metrics.rightSideBearing == 101423a0898aSmrg pci->metrics.leftSideBearing) 101523a0898aSmrg pci->metrics.rightSideBearing++; 101623a0898aSmrg if (pci->metrics.ascent == -pci->metrics.descent) 101723a0898aSmrg pci->metrics.ascent++; 101823a0898aSmrg } 101923a0898aSmrg 102023a0898aSmrg pci++; 102123a0898aSmrg } 102223a0898aSmrg } 102323a0898aSmrg 102423a0898aSmrg 102523a0898aSmrg /* 102623a0898aSmrg * For each character, set the per-character metrics, scale the glyph, and 102723a0898aSmrg * check per-font minbounds and maxbounds character information. 102823a0898aSmrg */ 102923a0898aSmrg 103023a0898aSmrg pci = bitmapFont->metrics; 103123a0898aSmrg for (i = 0; i < nchars; i++) 103223a0898aSmrg { 103323a0898aSmrg if ((pci = ACCESSENCODING(bitmapFont->encoding,i)) && 103423a0898aSmrg (opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i)))) 103523a0898aSmrg { 103623a0898aSmrg totalchars++; 103723a0898aSmrg *sWidth += abs((int)(INT16)pci->metrics.attributes); 103823a0898aSmrg#define MINMAX(field) \ 103923a0898aSmrg if (pfi->minbounds.field > pci->metrics.field) \ 104023a0898aSmrg pfi->minbounds.field = pci->metrics.field; \ 104123a0898aSmrg if (pfi->maxbounds.field < pci->metrics.field) \ 104223a0898aSmrg pfi->maxbounds.field = pci->metrics.field 104323a0898aSmrg 104423a0898aSmrg MINMAX(leftSideBearing); 104523a0898aSmrg MINMAX(rightSideBearing); 104623a0898aSmrg MINMAX(ascent); 104723a0898aSmrg MINMAX(descent); 104823a0898aSmrg MINMAX(characterWidth); 104923a0898aSmrg 105023a0898aSmrg /* Hack: Cast attributes into a signed quantity. Tread lightly 105123a0898aSmrg for now and don't go changing the global Xproto.h file */ 105223a0898aSmrg if ((INT16)pfi->minbounds.attributes > 105323a0898aSmrg (INT16)pci->metrics.attributes) 105423a0898aSmrg pfi->minbounds.attributes = pci->metrics.attributes; 105523a0898aSmrg if ((INT16)pfi->maxbounds.attributes < 105623a0898aSmrg (INT16)pci->metrics.attributes) 105723a0898aSmrg pfi->maxbounds.attributes = pci->metrics.attributes; 105823a0898aSmrg#undef MINMAX 105923a0898aSmrg } 106023a0898aSmrg } 106123a0898aSmrg pfi->ink_minbounds = pfi->minbounds; 106223a0898aSmrg pfi->ink_maxbounds = pfi->maxbounds; 106323a0898aSmrg if (totalchars) 106423a0898aSmrg { 106523a0898aSmrg *sWidth = (*sWidth * 10 + totalchars / 2) / totalchars; 106623a0898aSmrg if (totalwidth < 0) 106723a0898aSmrg { 106823a0898aSmrg /* Dominant direction is R->L */ 106923a0898aSmrg *sWidth = -*sWidth; 107023a0898aSmrg } 107123a0898aSmrg 107223a0898aSmrg if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth) 107323a0898aSmrg vals->width = pfi->minbounds.characterWidth * 10; 107423a0898aSmrg else 107523a0898aSmrg vals->width = doround((double)*sWidth * vals->pixel_matrix[0] / 107623a0898aSmrg 1000.0); 107723a0898aSmrg } 107823a0898aSmrg else 107923a0898aSmrg { 108023a0898aSmrg vals->width = 0; 108123a0898aSmrg *sWidth = 0; 108223a0898aSmrg } 108323a0898aSmrg FontComputeInfoAccelerators (pfi); 108423a0898aSmrg 108523a0898aSmrg if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) { 108623a0898aSmrg unsigned int r, 108723a0898aSmrg c, 108823a0898aSmrg cols; 108923a0898aSmrg 109023a0898aSmrg r = pfi->defaultCh >> 8; 109123a0898aSmrg c = pfi->defaultCh & 0xFF; 109223a0898aSmrg if (pfi->firstRow <= r && r <= pfi->lastRow && 109323a0898aSmrg pfi->firstCol <= c && c <= pfi->lastCol) { 109423a0898aSmrg cols = pfi->lastCol - pfi->firstCol + 1; 109523a0898aSmrg r = r - pfi->firstRow; 109623a0898aSmrg c = c - pfi->firstCol; 109723a0898aSmrg bitmapFont->pDefault = 109823a0898aSmrg ACCESSENCODING(bitmapFont->encoding, r * cols + c); 109923a0898aSmrg } 110023a0898aSmrg } 110123a0898aSmrg 110223a0898aSmrg *newWidthMult = xmult; 110323a0898aSmrg *newHeightMult = ymult; 110423a0898aSmrg return pf; 110523a0898aSmrgbail: 110623a0898aSmrg if (pf) 11077f7f5e4eSmrg free(pf); 110823a0898aSmrg if (bitmapFont) { 11097f7f5e4eSmrg free(bitmapFont->metrics); 11107f7f5e4eSmrg free(bitmapFont->ink_metrics); 11117f7f5e4eSmrg free(bitmapFont->bitmaps); 111223a0898aSmrg if(bitmapFont->encoding) 111323a0898aSmrg for(i=0; i<NUM_SEGMENTS(nchars); i++) 11147f7f5e4eSmrg free(bitmapFont->encoding[i]); 11157f7f5e4eSmrg free(bitmapFont->encoding); 111623a0898aSmrg } 111723a0898aSmrg return NULL; 111823a0898aSmrg} 111923a0898aSmrg 112023a0898aSmrgstatic void 112123a0898aSmrgScaleBitmap(FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci, 112223a0898aSmrg double *inv_xform, double widthMult, double heightMult) 112323a0898aSmrg{ 112423a0898aSmrg register char *bitmap, /* The bits */ 112523a0898aSmrg *newBitmap; 112623a0898aSmrg register int bpr, /* Padding information */ 112723a0898aSmrg newBpr; 112823a0898aSmrg int width, /* Extents information */ 112923a0898aSmrg height, 113023a0898aSmrg newWidth, 113123a0898aSmrg newHeight; 113223a0898aSmrg register int row, /* Loop variables */ 113323a0898aSmrg col; 113423a0898aSmrg INT32 deltaX, /* Increments for resampling loop */ 113523a0898aSmrg deltaY; 113623a0898aSmrg INT32 xValue, /* Subscripts for resampling loop */ 113723a0898aSmrg yValue; 113823a0898aSmrg double point[2]; 113923a0898aSmrg unsigned char *char_grayscale = 0; 114023a0898aSmrg INT32 *diffusion_workspace = NULL, *thisrow = NULL, 114123a0898aSmrg *nextrow = NULL, pixmult = 0; 114223a0898aSmrg int box_x = 0, box_y = 0; 114323a0898aSmrg 114423a0898aSmrg static unsigned char masklsb[] = 114523a0898aSmrg { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 }; 114623a0898aSmrg static unsigned char maskmsb[] = 114723a0898aSmrg { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; 114823a0898aSmrg unsigned char *mask = (pFont->bit == LSBFirst ? masklsb : maskmsb); 114923a0898aSmrg 115023a0898aSmrg 115123a0898aSmrg bitmap = opci->bits; 115223a0898aSmrg newBitmap = pci->bits; 115323a0898aSmrg width = GLYPHWIDTHPIXELS(opci); 115423a0898aSmrg height = GLYPHHEIGHTPIXELS(opci); 115523a0898aSmrg newWidth = GLYPHWIDTHPIXELS(pci); 115623a0898aSmrg newHeight = GLYPHHEIGHTPIXELS(pci); 115723a0898aSmrg if (!newWidth || !newHeight || !width || !height) 115823a0898aSmrg return; 115923a0898aSmrg 116023a0898aSmrg bpr = BYTES_PER_ROW(width, pFont->glyph); 116123a0898aSmrg newBpr = BYTES_PER_ROW(newWidth, pFont->glyph); 116223a0898aSmrg 116323a0898aSmrg if (widthMult > 0.0 && heightMult > 0.0 && 116423a0898aSmrg (widthMult < 1.0 || heightMult < 1.0)) 116523a0898aSmrg { 116623a0898aSmrg /* We are reducing in one or both dimensions. In an attempt to 116723a0898aSmrg reduce aliasing, we'll antialias by passing the original 116823a0898aSmrg glyph through a low-pass box filter (which results in a 116923a0898aSmrg grayscale image), then use error diffusion to create bitonal 117023a0898aSmrg output in the resampling loop. */ 117123a0898aSmrg 117223a0898aSmrg /* First compute the sizes of the box filter */ 117323a0898aSmrg widthMult = ceil(1.0 / widthMult); 117423a0898aSmrg heightMult = ceil(1.0 / heightMult); 117523a0898aSmrg box_x = width / 2; 117623a0898aSmrg box_y = height / 2; 117723a0898aSmrg if (widthMult < (double)box_x) box_x = (int)widthMult; 117823a0898aSmrg if (heightMult < (double)box_y) box_y = (int)heightMult; 117923a0898aSmrg /* The pixmult value (below) is used to darken the image before 118023a0898aSmrg we perform error diffusion: a necessary concession to the 118123a0898aSmrg fact that it's very difficult to generate readable halftoned 118223a0898aSmrg glyphs. The degree of darkening is proportional to the size 118323a0898aSmrg of the blurring filter, hence inversely proportional to the 118423a0898aSmrg darkness of the lightest gray that results from antialiasing. 118523a0898aSmrg The result is that characters that exercise this logic (those 118623a0898aSmrg generated by reducing from a larger source font) tend to err 118723a0898aSmrg on the side of being too bold instead of being too light to 118823a0898aSmrg be readable. */ 118923a0898aSmrg pixmult = box_x * box_y * 192; 119023a0898aSmrg 119123a0898aSmrg if (box_x > 1 || box_y > 1) 119223a0898aSmrg { 119323a0898aSmrg /* Looks like we need to anti-alias. Create a workspace to 119423a0898aSmrg contain the grayscale character plus an additional row and 119523a0898aSmrg column for scratch */ 11967f7f5e4eSmrg char_grayscale = malloc((width + 1) * (height + 1)); 119723a0898aSmrg if (char_grayscale) 119823a0898aSmrg { 11997f7f5e4eSmrg diffusion_workspace = calloc((newWidth + 2) * 2, sizeof(int)); 120023a0898aSmrg if (!diffusion_workspace) 120123a0898aSmrg { 120223a0898aSmrg fprintf(stderr, "Warning: Couldn't allocate diffusion" 120323a0898aSmrg " workspace (%ld)\n", 120423a0898aSmrg (newWidth + 2) * 2 * (unsigned long)sizeof(int)); 12057f7f5e4eSmrg free(char_grayscale); 120623a0898aSmrg char_grayscale = (unsigned char *)0; 120723a0898aSmrg } 120823a0898aSmrg /* Initialize our error diffusion workspace for later use */ 120923a0898aSmrg thisrow = diffusion_workspace + 1; 121023a0898aSmrg nextrow = diffusion_workspace + newWidth + 3; 121123a0898aSmrg } else { 121223a0898aSmrg fprintf(stderr, "Warning: Couldn't allocate character grayscale (%d)\n", (width + 1) * (height + 1)); 121323a0898aSmrg } 121423a0898aSmrg } 121523a0898aSmrg } 121623a0898aSmrg 121723a0898aSmrg if (char_grayscale) 121823a0898aSmrg { 121923a0898aSmrg /* We will be doing antialiasing. First copy the bitmap into 122023a0898aSmrg our buffer, mapping input range [0,1] to output range 122123a0898aSmrg [0,255]. */ 122223a0898aSmrg register unsigned char *srcptr, *dstptr; 122323a0898aSmrg srcptr = (unsigned char *)bitmap; 122423a0898aSmrg dstptr = char_grayscale; 122523a0898aSmrg for (row = 0; row < height; row++) 122623a0898aSmrg { 122723a0898aSmrg for (col = 0; col < width; col++) 122823a0898aSmrg *dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0; 122923a0898aSmrg srcptr += bpr; /* On to next row of source */ 123023a0898aSmrg dstptr++; /* Skip scratch column in dest */ 123123a0898aSmrg } 123223a0898aSmrg if (box_x > 1) 123323a0898aSmrg { 123423a0898aSmrg /* Our box filter has a width > 1... let's filter the rows */ 123523a0898aSmrg 123623a0898aSmrg int right_width = box_x / 2; 123723a0898aSmrg int left_width = box_x - right_width - 1; 123823a0898aSmrg 123923a0898aSmrg for (row = 0; row < height; row++) 124023a0898aSmrg { 124123a0898aSmrg int sum = 0; 124223a0898aSmrg int left_size = 0, right_size = 0; 124323a0898aSmrg 124423a0898aSmrg srcptr = char_grayscale + (width + 1) * row; 124523a0898aSmrg dstptr = char_grayscale + (width + 1) * height; /* scratch */ 124623a0898aSmrg 124723a0898aSmrg /* We've computed the shape of our full box filter. Now 124823a0898aSmrg compute the right-hand part of the moving sum */ 124923a0898aSmrg for (right_size = 0; right_size < right_width; right_size++) 125023a0898aSmrg sum += srcptr[right_size]; 125123a0898aSmrg 125223a0898aSmrg /* Now start moving the sum, growing the box filter, and 125323a0898aSmrg dropping averages into our scratch buffer */ 125423a0898aSmrg for (left_size = 0; left_size < left_width; left_size++) 125523a0898aSmrg { 125623a0898aSmrg sum += srcptr[right_width]; 125723a0898aSmrg *dstptr++ = sum / (left_size + right_width + 1); 125823a0898aSmrg srcptr++; 125923a0898aSmrg } 126023a0898aSmrg 126123a0898aSmrg /* The box filter has reached full width... continue 126223a0898aSmrg computation of moving average until the right side 126323a0898aSmrg hits the wall. */ 126423a0898aSmrg for (col = left_size; col + right_size < width; col++) 126523a0898aSmrg { 126623a0898aSmrg sum += srcptr[right_width]; 126723a0898aSmrg *dstptr++ = sum / box_x; 126823a0898aSmrg sum -= srcptr[-left_width]; 126923a0898aSmrg srcptr++; 127023a0898aSmrg } 127123a0898aSmrg 127223a0898aSmrg /* Collapse the right side of the box filter */ 127323a0898aSmrg for (; right_size > 0; right_size--) 127423a0898aSmrg { 127523a0898aSmrg *dstptr++ = sum / (left_width + right_size); 127623a0898aSmrg sum -= srcptr[-left_width]; 127723a0898aSmrg srcptr++; 127823a0898aSmrg } 127923a0898aSmrg 128023a0898aSmrg /* Done with the row... copy dest back over source */ 128123a0898aSmrg memmove(char_grayscale + (width + 1) * row, 128223a0898aSmrg char_grayscale + (width + 1) * height, 128323a0898aSmrg width); 128423a0898aSmrg } 128523a0898aSmrg } 128623a0898aSmrg if (box_y > 1) 128723a0898aSmrg { 128823a0898aSmrg /* Our box filter has a height > 1... let's filter the columns */ 128923a0898aSmrg 129023a0898aSmrg int bottom_height = box_y / 2; 129123a0898aSmrg int top_height = box_y - bottom_height - 1; 129223a0898aSmrg 129323a0898aSmrg for (col = 0; col < width; col++) 129423a0898aSmrg { 129523a0898aSmrg int sum = 0; 129623a0898aSmrg int top_size = 0, bottom_size = 0; 129723a0898aSmrg 129823a0898aSmrg srcptr = char_grayscale + col; 129923a0898aSmrg dstptr = char_grayscale + width; /* scratch */ 130023a0898aSmrg 130123a0898aSmrg /* We've computed the shape of our full box filter. Now 130223a0898aSmrg compute the bottom part of the moving sum */ 130323a0898aSmrg for (bottom_size = 0; 130423a0898aSmrg bottom_size < bottom_height; 130523a0898aSmrg bottom_size++) 130623a0898aSmrg sum += srcptr[bottom_size * (width + 1)]; 130723a0898aSmrg 130823a0898aSmrg /* Now start moving the sum, growing the box filter, and 130923a0898aSmrg dropping averages into our scratch buffer */ 131023a0898aSmrg for (top_size = 0; top_size < top_height; top_size++) 131123a0898aSmrg { 131223a0898aSmrg sum += srcptr[bottom_height * (width + 1)]; 131323a0898aSmrg *dstptr = sum / (top_size + bottom_height + 1); 131423a0898aSmrg dstptr += width + 1; 131523a0898aSmrg srcptr += width + 1; 131623a0898aSmrg } 131723a0898aSmrg 131823a0898aSmrg /* The box filter has reached full height... continue 131923a0898aSmrg computation of moving average until the bottom 132023a0898aSmrg hits the wall. */ 132123a0898aSmrg for (row = top_size; row + bottom_size < height; row++) 132223a0898aSmrg { 132323a0898aSmrg sum += srcptr[bottom_height * (width + 1)]; 132423a0898aSmrg *dstptr = sum / box_y; 132523a0898aSmrg dstptr += width + 1; 132623a0898aSmrg sum -= srcptr[-top_height * (width + 1)]; 132723a0898aSmrg srcptr += width + 1; 132823a0898aSmrg } 132923a0898aSmrg 133023a0898aSmrg /* Collapse the bottom of the box filter */ 133123a0898aSmrg for (; bottom_size > 0; bottom_size--) 133223a0898aSmrg { 133323a0898aSmrg *dstptr = sum / (top_height + bottom_size); 133423a0898aSmrg dstptr += width + 1; 133523a0898aSmrg sum -= srcptr[-top_height * (width + 1)]; 133623a0898aSmrg srcptr += width + 1; 133723a0898aSmrg } 133823a0898aSmrg 133923a0898aSmrg /* Done with the column... copy dest back over source */ 134023a0898aSmrg 134123a0898aSmrg dstptr = char_grayscale + col; 134223a0898aSmrg srcptr = char_grayscale + width; /* scratch */ 134323a0898aSmrg for (row = 0; row < height; row++) 134423a0898aSmrg { 134523a0898aSmrg *dstptr = *srcptr; 134623a0898aSmrg dstptr += width + 1; 134723a0898aSmrg srcptr += width + 1; 134823a0898aSmrg } 134923a0898aSmrg } 135023a0898aSmrg } 135123a0898aSmrg 135223a0898aSmrg /* Increase the grayvalue to increase ink a bit */ 135323a0898aSmrg srcptr = char_grayscale; 135423a0898aSmrg for (row = 0; row < height; row++) 135523a0898aSmrg { 135623a0898aSmrg for (col = 0; col < width; col++) 135723a0898aSmrg { 135823a0898aSmrg register int pixvalue = (int)*srcptr * pixmult / 256; 135923a0898aSmrg if (pixvalue > 255) pixvalue = 255; 136023a0898aSmrg *srcptr = pixvalue; 136123a0898aSmrg srcptr++; 136223a0898aSmrg } 136323a0898aSmrg srcptr++; 136423a0898aSmrg } 136523a0898aSmrg } 136623a0898aSmrg 136723a0898aSmrg /* Compute the increment values for the resampling loop */ 136823a0898aSmrg TRANSFORM_POINT(inv_xform, 1, 0, point); 136923a0898aSmrg deltaX = (INT32)(point[0] * 65536.0); 137023a0898aSmrg deltaY = (INT32)(-point[1] * 65536.0); 137123a0898aSmrg 137223a0898aSmrg /* Resampling loop: resamples original glyph for generation of new 137323a0898aSmrg glyph in transformed coordinate system. */ 137423a0898aSmrg 137523a0898aSmrg for (row = 0; row < newHeight; row++) 137623a0898aSmrg { 137723a0898aSmrg /* Compute inverse transformation for start of this row */ 137823a0898aSmrg TRANSFORM_POINT(inv_xform, 137923a0898aSmrg (double)(pci->metrics.leftSideBearing) + .5, 138023a0898aSmrg (double)(pci->metrics.ascent - row) - .5, 138123a0898aSmrg point); 138223a0898aSmrg 138323a0898aSmrg /* Adjust for coordinate system to get resampling point */ 138423a0898aSmrg point[0] -= opci->metrics.leftSideBearing; 138523a0898aSmrg point[1] = opci->metrics.ascent - point[1]; 138623a0898aSmrg 138723a0898aSmrg /* Convert to integer coordinates */ 138823a0898aSmrg xValue = (INT32)(point[0] * 65536.0); 138923a0898aSmrg yValue = (INT32)(point[1] * 65536.0); 139023a0898aSmrg 139123a0898aSmrg if (char_grayscale) 139223a0898aSmrg { 139323a0898aSmrg INT32 *temp; 139423a0898aSmrg for (col = 0; col < newWidth; col++) 139523a0898aSmrg { 139623a0898aSmrg register int x = xValue >> 16, y = yValue >> 16; 139723a0898aSmrg int pixvalue, error; 139823a0898aSmrg 139923a0898aSmrg pixvalue = ((x >= 0 && x < width && y >= 0 && y < height) ? 140023a0898aSmrg char_grayscale[x + y * (width + 1)] : 0) + 140123a0898aSmrg thisrow[col] / 16; 140223a0898aSmrg if (pixvalue > 255) pixvalue = 255; 140323a0898aSmrg else if (pixvalue < 0) pixvalue = 0; 140423a0898aSmrg 140523a0898aSmrg /* Choose the bit value and set resulting error value */ 140623a0898aSmrg if (pixvalue >= 128) 140723a0898aSmrg { 140823a0898aSmrg newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7]; 140923a0898aSmrg error = pixvalue - 255; 141023a0898aSmrg } 141123a0898aSmrg else 141223a0898aSmrg error = -pixvalue; 141323a0898aSmrg 141423a0898aSmrg /* Diffuse the error */ 141523a0898aSmrg thisrow[col + 1] += error * 7; 141623a0898aSmrg nextrow[col - 1] += error * 3; 141723a0898aSmrg nextrow[col] += error * 5; 141823a0898aSmrg nextrow[col + 1] = error; 141923a0898aSmrg 142023a0898aSmrg xValue += deltaX; 142123a0898aSmrg yValue += deltaY; 142223a0898aSmrg } 142323a0898aSmrg 142423a0898aSmrg /* Add in error values that fell off either end */ 142523a0898aSmrg nextrow[0] += nextrow[-1]; 142623a0898aSmrg nextrow[newWidth - 2] += thisrow[newWidth]; 142723a0898aSmrg nextrow[newWidth - 1] += nextrow[newWidth]; 142823a0898aSmrg nextrow[newWidth] = 0; 142923a0898aSmrg 143023a0898aSmrg temp = nextrow; 143123a0898aSmrg nextrow = thisrow; 143223a0898aSmrg thisrow = temp; 143323a0898aSmrg nextrow[-1] = nextrow[0] = 0; 143423a0898aSmrg } 143523a0898aSmrg else 143623a0898aSmrg { 143723a0898aSmrg for (col = 0; col < newWidth; col++) 143823a0898aSmrg { 143923a0898aSmrg register int x = xValue >> 16, y = yValue >> 16; 144023a0898aSmrg 144123a0898aSmrg if (x >= 0 && x < width && y >= 0 && y < height) 144223a0898aSmrg { 144323a0898aSmrg /* Use point-sampling for rescaling. */ 144423a0898aSmrg 144523a0898aSmrg if (bitmap[(x >> 3) + y * bpr] & mask[x & 0x7]) 144623a0898aSmrg newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7]; 144723a0898aSmrg } 144823a0898aSmrg 144923a0898aSmrg xValue += deltaX; 145023a0898aSmrg yValue += deltaY; 145123a0898aSmrg } 145223a0898aSmrg } 145323a0898aSmrg } 145423a0898aSmrg 145523a0898aSmrg 145623a0898aSmrg if (char_grayscale) 145723a0898aSmrg { 14587f7f5e4eSmrg free(char_grayscale); 14597f7f5e4eSmrg free(diffusion_workspace); 146023a0898aSmrg } 146123a0898aSmrg} 146223a0898aSmrg 146323a0898aSmrgstatic FontPtr 146423a0898aSmrgBitmapScaleBitmaps(FontPtr pf, /* scaled font */ 146523a0898aSmrg FontPtr opf, /* originating font */ 146623a0898aSmrg double widthMult, /* glyphs width scale factor */ 146723a0898aSmrg double heightMult, /* glyphs height scale factor */ 146823a0898aSmrg FontScalablePtr vals) 146923a0898aSmrg{ 147023a0898aSmrg register int i; 147123a0898aSmrg int nchars = 0; 147223a0898aSmrg char *glyphBytes; 147323a0898aSmrg BitmapFontPtr bitmapFont, 147423a0898aSmrg obitmapFont; 147523a0898aSmrg CharInfoPtr pci, 147623a0898aSmrg opci; 147723a0898aSmrg FontInfoPtr pfi; 147823a0898aSmrg int glyph; 147923a0898aSmrg unsigned bytestoalloc = 0; 148023a0898aSmrg int firstCol, lastCol, firstRow, lastRow; 148123a0898aSmrg 148223a0898aSmrg double xform[4], inv_xform[4]; 148323a0898aSmrg double xmult, ymult; 148423a0898aSmrg 148523a0898aSmrg bitmapFont = (BitmapFontPtr) pf->fontPrivate; 148623a0898aSmrg obitmapFont = (BitmapFontPtr) opf->fontPrivate; 148723a0898aSmrg 148823a0898aSmrg if (!compute_xform_matrix(vals, widthMult, heightMult, xform, 148923a0898aSmrg inv_xform, &xmult, &ymult)) 149023a0898aSmrg goto bail; 149123a0898aSmrg 149223a0898aSmrg pfi = &pf->info; 149323a0898aSmrg firstCol = pfi->firstCol; 149423a0898aSmrg lastCol = pfi->lastCol; 149523a0898aSmrg firstRow = pfi->firstRow; 149623a0898aSmrg lastRow = pfi->lastRow; 149723a0898aSmrg 149823a0898aSmrg nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); 149923a0898aSmrg glyph = pf->glyph; 150023a0898aSmrg for (i = 0; i < nchars; i++) 150123a0898aSmrg { 150223a0898aSmrg if ((pci = ACCESSENCODING(bitmapFont->encoding, i))) 150323a0898aSmrg bytestoalloc += BYTES_FOR_GLYPH(pci, glyph); 150423a0898aSmrg } 150523a0898aSmrg 150623a0898aSmrg /* Do we add the font malloc stuff for VALUE ADDED ? */ 150723a0898aSmrg /* Will need to remember to free in the Unload routine */ 150823a0898aSmrg 150923a0898aSmrg 15107f7f5e4eSmrg bitmapFont->bitmaps = calloc(1, bytestoalloc); 151123a0898aSmrg if (!bitmapFont->bitmaps) { 151223a0898aSmrg fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc); 151323a0898aSmrg goto bail; 151423a0898aSmrg } 151523a0898aSmrg 151623a0898aSmrg glyphBytes = bitmapFont->bitmaps; 151723a0898aSmrg for (i = 0; i < nchars; i++) 151823a0898aSmrg { 151923a0898aSmrg if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) && 152023a0898aSmrg (opci = ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i)))) 152123a0898aSmrg { 152223a0898aSmrg pci->bits = glyphBytes; 152323a0898aSmrg ScaleBitmap (pf, opci, pci, inv_xform, 152423a0898aSmrg widthMult, heightMult); 152523a0898aSmrg glyphBytes += BYTES_FOR_GLYPH(pci, glyph); 152623a0898aSmrg } 152723a0898aSmrg } 152823a0898aSmrg return pf; 152923a0898aSmrg 153023a0898aSmrgbail: 153123a0898aSmrg if (pf) 15327f7f5e4eSmrg free(pf); 153323a0898aSmrg if (bitmapFont) { 15347f7f5e4eSmrg free(bitmapFont->metrics); 15357f7f5e4eSmrg free(bitmapFont->ink_metrics); 15367f7f5e4eSmrg free(bitmapFont->bitmaps); 153723a0898aSmrg if(bitmapFont->encoding) 153823a0898aSmrg for(i=0; i<NUM_SEGMENTS(nchars); i++) 15397f7f5e4eSmrg free(bitmapFont->encoding[i]); 15407f7f5e4eSmrg free(bitmapFont->encoding); 154123a0898aSmrg } 154223a0898aSmrg return NULL; 154323a0898aSmrg} 154423a0898aSmrg 154523a0898aSmrg/* ARGSUSED */ 154623a0898aSmrgint 154723a0898aSmrgBitmapOpenScalable (FontPathElementPtr fpe, 154823a0898aSmrg FontPtr *pFont, 154923a0898aSmrg int flags, 155023a0898aSmrg FontEntryPtr entry, 155123a0898aSmrg char *fileName, /* unused */ 155223a0898aSmrg FontScalablePtr vals, 155323a0898aSmrg fsBitmapFormat format, 155423a0898aSmrg fsBitmapFormatMask fmask, 155523a0898aSmrg FontPtr non_cachable_font) /* We don't do licensing */ 155623a0898aSmrg{ 155723a0898aSmrg FontScalableRec best; 155823a0898aSmrg FontPtr font = NullFont; 155923a0898aSmrg double dx, sdx, 156023a0898aSmrg dy, sdy, 156123a0898aSmrg savedX, savedY; 156223a0898aSmrg FontPropPtr props; 156323a0898aSmrg char *isStringProp = NULL; 156423a0898aSmrg int propCount; 156523a0898aSmrg int status; 156623a0898aSmrg long sWidth; 156723a0898aSmrg 156823a0898aSmrg FontEntryPtr scaleFrom; 15697f7f5e4eSmrg FontPathElementPtr scaleFPE = NULL; 157023a0898aSmrg FontPtr sourceFont; 157123a0898aSmrg char fontName[MAXFONTNAMELEN]; 157223a0898aSmrg 157323a0898aSmrg /* Can't deal with mix-endian fonts yet */ 157423a0898aSmrg 157523a0898aSmrg 157623a0898aSmrg /* Reject outrageously small font sizes to keep the math from 157723a0898aSmrg blowing up. */ 157823a0898aSmrg if (get_matrix_vertical_component(vals->pixel_matrix) < 1.0 || 157923a0898aSmrg get_matrix_horizontal_component(vals->pixel_matrix) < 1.0) 158023a0898aSmrg return BadFontName; 158123a0898aSmrg 15827f7f5e4eSmrg scaleFrom = FindBestToScale(fpe, entry, vals, &best, &dx, &dy, &sdx, &sdy, 15837f7f5e4eSmrg &scaleFPE); 158423a0898aSmrg 158523a0898aSmrg if (!scaleFrom) 158623a0898aSmrg return BadFontName; 158723a0898aSmrg 158823a0898aSmrg status = FontFileOpenBitmap(scaleFPE, &sourceFont, LoadAll, scaleFrom, 158923a0898aSmrg format, fmask); 159023a0898aSmrg 159123a0898aSmrg if (status != Successful) 159223a0898aSmrg return BadFontName; 159323a0898aSmrg 159423a0898aSmrg if (!vals->width) 159523a0898aSmrg vals->width = best.width * dx; 159623a0898aSmrg 159723a0898aSmrg /* Compute the scaled font */ 159823a0898aSmrg 159923a0898aSmrg savedX = dx; 160023a0898aSmrg savedY = dy; 160123a0898aSmrg font = ScaleFont(sourceFont, dx, dy, sdx, sdy, vals, &dx, &dy, &sWidth); 160223a0898aSmrg if (font) 16037f7f5e4eSmrg font = BitmapScaleBitmaps(font, sourceFont, savedX, savedY, vals); 160423a0898aSmrg 160523a0898aSmrg if (!font) 160623a0898aSmrg { 160723a0898aSmrg if (!sourceFont->refcnt) 160823a0898aSmrg FontFileCloseFont((FontPathElementPtr) 0, sourceFont); 160923a0898aSmrg return AllocError; 161023a0898aSmrg } 161123a0898aSmrg 161223a0898aSmrg /* Prepare font properties for the new font */ 161323a0898aSmrg 161423a0898aSmrg strcpy (fontName, scaleFrom->name.name); 161523a0898aSmrg FontParseXLFDName (fontName, vals, FONT_XLFD_REPLACE_VALUE); 161623a0898aSmrg 161723a0898aSmrg propCount = ComputeScaledProperties(&sourceFont->info, fontName, vals, 161823a0898aSmrg dx, dy, sdx, sdy, sWidth, &props, 161923a0898aSmrg &isStringProp); 162023a0898aSmrg 162123a0898aSmrg if (!sourceFont->refcnt) 162223a0898aSmrg FontFileCloseFont((FontPathElementPtr) 0, sourceFont); 162323a0898aSmrg 162423a0898aSmrg if (propCount && (!props || !isStringProp)) 162523a0898aSmrg { 162623a0898aSmrg font->info.nprops = 0; 162723a0898aSmrg font->info.props = (FontPropPtr)0; 162823a0898aSmrg font->info.isStringProp = (char *)0; 162923a0898aSmrg bitmapUnloadScalable(font); 163023a0898aSmrg return AllocError; 163123a0898aSmrg } 163223a0898aSmrg 163323a0898aSmrg font->info.props = props; 163423a0898aSmrg font->info.nprops = propCount; 163523a0898aSmrg font->info.isStringProp = isStringProp; 163623a0898aSmrg 163723a0898aSmrg *pFont = font; 163823a0898aSmrg return Successful; 163923a0898aSmrg} 164023a0898aSmrg 164123a0898aSmrgint 164223a0898aSmrgBitmapGetInfoScalable (FontPathElementPtr fpe, 164323a0898aSmrg FontInfoPtr pFontInfo, 164423a0898aSmrg FontEntryPtr entry, 164523a0898aSmrg FontNamePtr fontName, 164623a0898aSmrg char *fileName, 164723a0898aSmrg FontScalablePtr vals) 164823a0898aSmrg{ 164923a0898aSmrg FontPtr pfont; 165023a0898aSmrg int flags = 0; 165123a0898aSmrg long format = 0; /* It doesn't matter what format for just info */ 165223a0898aSmrg long fmask = 0; 165323a0898aSmrg int ret; 165423a0898aSmrg 165523a0898aSmrg ret = BitmapOpenScalable(fpe, &pfont, flags, entry, fileName, vals, 165623a0898aSmrg format, fmask, NULL); 165723a0898aSmrg if (ret != Successful) 165823a0898aSmrg return ret; 165923a0898aSmrg *pFontInfo = pfont->info; 166023a0898aSmrg 166123a0898aSmrg pfont->info.nprops = 0; 166223a0898aSmrg pfont->info.props = NULL; 166323a0898aSmrg pfont->info.isStringProp = NULL; 166423a0898aSmrg 166523a0898aSmrg (*pfont->unload_font)(pfont); 166623a0898aSmrg return Successful; 166723a0898aSmrg} 166823a0898aSmrg 166923a0898aSmrgstatic void 167023a0898aSmrgbitmapUnloadScalable (FontPtr pFont) 167123a0898aSmrg{ 167223a0898aSmrg BitmapFontPtr bitmapFont; 167323a0898aSmrg FontInfoPtr pfi; 167423a0898aSmrg int i, nencoding; 167523a0898aSmrg 167623a0898aSmrg bitmapFont = (BitmapFontPtr) pFont->fontPrivate; 167723a0898aSmrg pfi = &pFont->info; 16787f7f5e4eSmrg free (pfi->props); 16797f7f5e4eSmrg free (pfi->isStringProp); 168023a0898aSmrg if(bitmapFont->encoding) { 168123a0898aSmrg nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) * 168223a0898aSmrg (pFont->info.lastRow - pFont->info.firstRow + 1); 168323a0898aSmrg for(i=0; i<NUM_SEGMENTS(nencoding); i++) 16847f7f5e4eSmrg free(bitmapFont->encoding[i]); 168523a0898aSmrg } 16867f7f5e4eSmrg free (bitmapFont->encoding); 16877f7f5e4eSmrg free (bitmapFont->bitmaps); 16887f7f5e4eSmrg free (bitmapFont->ink_metrics); 16897f7f5e4eSmrg free (bitmapFont->metrics); 16907f7f5e4eSmrg free (pFont->fontPrivate); 169123a0898aSmrg DestroyFontRec (pFont); 169223a0898aSmrg} 1693