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