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