bitscale.c revision a96d7823
1a96d7823Smrg/* 2a96d7823Smrg 3a96d7823SmrgCopyright 1991, 1994, 1998 The Open Group 4a96d7823Smrg 5a96d7823SmrgPermission to use, copy, modify, distribute, and sell this software and its 6a96d7823Smrgdocumentation for any purpose is hereby granted without fee, provided that 7a96d7823Smrgthe above copyright notice appear in all copies and that both that 8a96d7823Smrgcopyright notice and this permission notice appear in supporting 9a96d7823Smrgdocumentation. 10a96d7823Smrg 11a96d7823SmrgThe above copyright notice and this permission notice shall be included 12a96d7823Smrgin all copies or substantial portions of the Software. 13a96d7823Smrg 14a96d7823SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15a96d7823SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16a96d7823SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17a96d7823SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18a96d7823SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19a96d7823SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20a96d7823SmrgOTHER DEALINGS IN THE SOFTWARE. 21a96d7823Smrg 22a96d7823SmrgExcept as contained in this notice, the name of The Open Group shall 23a96d7823Smrgnot be used in advertising or otherwise to promote the sale, use or 24a96d7823Smrgother dealings in this Software without prior written authorization 25a96d7823Smrgfrom The Open Group. 26a96d7823Smrg 27a96d7823Smrg*/ 28a96d7823Smrg 29a96d7823Smrg/* 30a96d7823Smrg * Author: Keith Packard, MIT X Consortium 31a96d7823Smrg */ 32a96d7823Smrg 33a96d7823Smrg#ifdef HAVE_CONFIG_H 34a96d7823Smrg#include <config.h> 35a96d7823Smrg#endif 36a96d7823Smrg#include "libxfontint.h" 37a96d7823Smrg 38a96d7823Smrg#include <X11/fonts/fntfilst.h> 39a96d7823Smrg#include <X11/fonts/bitmap.h> 40a96d7823Smrg#include <X11/fonts/fontutil.h> 41a96d7823Smrg#include <math.h> 42a96d7823Smrg 43a96d7823Smrg#ifndef MAX 44a96d7823Smrg#define MAX(a,b) (((a)>(b)) ? a : b) 45a96d7823Smrg#endif 46a96d7823Smrg 47a96d7823Smrgstatic void bitmapUnloadScalable (FontPtr pFont); 48a96d7823Smrgstatic void ScaleBitmap ( FontPtr pFont, CharInfoPtr opci, 49a96d7823Smrg CharInfoPtr pci, double *inv_xform, 50a96d7823Smrg double widthMult, double heightMult ); 51a96d7823Smrgstatic FontPtr BitmapScaleBitmaps(FontPtr pf, FontPtr opf, 52a96d7823Smrg double widthMult, double heightMult, 53a96d7823Smrg FontScalablePtr vals); 54a96d7823Smrg 55a96d7823Smrgenum scaleType { 56a96d7823Smrg atom, truncate_atom, pixel_size, point_size, resolution_x, 57a96d7823Smrg resolution_y, average_width, scaledX, scaledY, unscaled, fontname, 58a96d7823Smrg raw_ascent, raw_descent, raw_pixelsize, raw_pointsize, 59a96d7823Smrg raw_average_width, uncomputed 60a96d7823Smrg}; 61a96d7823Smrg 62a96d7823Smrgtypedef struct _fontProp { 63a96d7823Smrg const char *name; 64a96d7823Smrg Atom atom; 65a96d7823Smrg enum scaleType type; 66a96d7823Smrg} fontProp; 67a96d7823Smrg 68a96d7823Smrgstatic FontEntryPtr FindBestToScale ( FontPathElementPtr fpe, 69a96d7823Smrg FontEntryPtr entry, 70a96d7823Smrg FontScalablePtr vals, 71a96d7823Smrg FontScalablePtr best, 72a96d7823Smrg double *dxp, double *dyp, 73a96d7823Smrg double *sdxp, double *sdyp, 74a96d7823Smrg FontPathElementPtr *fpep ); 75a96d7823Smrg 76a96d7823Smrgstatic unsigned long bitscaleGeneration = 0; /* initialization flag */ 77a96d7823Smrg 78a96d7823Smrgstatic fontProp fontNamePropTable[] = { 79a96d7823Smrg { "FOUNDRY", 0, atom }, 80a96d7823Smrg { "FAMILY_NAME", 0, atom }, 81a96d7823Smrg { "WEIGHT_NAME", 0, atom }, 82a96d7823Smrg { "SLANT", 0, atom }, 83a96d7823Smrg { "SETWIDTH_NAME", 0, atom }, 84a96d7823Smrg { "ADD_STYLE_NAME", 0, atom }, 85a96d7823Smrg { "PIXEL_SIZE", 0, pixel_size }, 86a96d7823Smrg { "POINT_SIZE", 0, point_size }, 87a96d7823Smrg { "RESOLUTION_X", 0, resolution_x }, 88a96d7823Smrg { "RESOLUTION_Y", 0, resolution_y }, 89a96d7823Smrg { "SPACING", 0, atom }, 90a96d7823Smrg { "AVERAGE_WIDTH", 0, average_width }, 91a96d7823Smrg { "CHARSET_REGISTRY", 0, atom }, 92a96d7823Smrg { "CHARSET_ENCODING", 0, truncate_atom }, 93a96d7823Smrg { "FONT", 0, fontname }, 94a96d7823Smrg { "RAW_ASCENT", 0, raw_ascent }, 95a96d7823Smrg { "RAW_DESCENT", 0, raw_descent }, 96a96d7823Smrg { "RAW_PIXEL_SIZE", 0, raw_pixelsize }, 97a96d7823Smrg { "RAW_POINT_SIZE", 0, raw_pointsize }, 98a96d7823Smrg { "RAW_AVERAGE_WIDTH", 0, raw_average_width } 99a96d7823Smrg}; 100a96d7823Smrg 101a96d7823Smrg#define TRANSFORM_POINT(matrix, x, y, dest) \ 102a96d7823Smrg ((dest)[0] = (matrix)[0] * (x) + (matrix)[2] * (y), \ 103a96d7823Smrg (dest)[1] = (matrix)[1] * (x) + (matrix)[3] * (y)) 104a96d7823Smrg 105a96d7823Smrg#define CHECK_EXTENT(lsb, rsb, desc, asc, data) \ 106a96d7823Smrg ((lsb) > (data)[0] ? (lsb) = (data)[0] : 0 , \ 107a96d7823Smrg (rsb) < (data)[0] ? (rsb) = (data)[0] : 0, \ 108a96d7823Smrg (-desc) > (data)[1] ? (desc) = -(data)[1] : 0 , \ 109a96d7823Smrg (asc) < (data)[1] ? (asc) = (data)[1] : 0) 110a96d7823Smrg 111a96d7823Smrg#define NPROPS (sizeof(fontNamePropTable) / sizeof(fontProp)) 112a96d7823Smrg 113a96d7823Smrg/* Warning: order of the next two tables is critically interdependent. 114a96d7823Smrg Location of "unscaled" properties at the end of fontPropTable[] 115a96d7823Smrg is important. */ 116a96d7823Smrg 117a96d7823Smrgstatic fontProp fontPropTable[] = { 118a96d7823Smrg { "MIN_SPACE", 0, scaledX }, 119a96d7823Smrg { "NORM_SPACE", 0, scaledX }, 120a96d7823Smrg { "MAX_SPACE", 0, scaledX }, 121a96d7823Smrg { "END_SPACE", 0, scaledX }, 122a96d7823Smrg { "AVG_CAPITAL_WIDTH", 0, scaledX }, 123a96d7823Smrg { "AVG_LOWERCASE_WIDTH", 0, scaledX }, 124a96d7823Smrg { "QUAD_WIDTH", 0, scaledX }, 125a96d7823Smrg { "FIGURE_WIDTH", 0, scaledX }, 126a96d7823Smrg { "SUPERSCRIPT_X", 0, scaledX }, 127a96d7823Smrg { "SUPERSCRIPT_Y", 0, scaledY }, 128a96d7823Smrg { "SUBSCRIPT_X", 0, scaledX }, 129a96d7823Smrg { "SUBSCRIPT_Y", 0, scaledY }, 130a96d7823Smrg { "SUPERSCRIPT_SIZE", 0, scaledY }, 131a96d7823Smrg { "SUBSCRIPT_SIZE", 0, scaledY }, 132a96d7823Smrg { "SMALL_CAP_SIZE", 0, scaledY }, 133a96d7823Smrg { "UNDERLINE_POSITION", 0, scaledY }, 134a96d7823Smrg { "UNDERLINE_THICKNESS", 0, scaledY }, 135a96d7823Smrg { "STRIKEOUT_ASCENT", 0, scaledY }, 136a96d7823Smrg { "STRIKEOUT_DESCENT", 0, scaledY }, 137a96d7823Smrg { "CAP_HEIGHT", 0, scaledY }, 138a96d7823Smrg { "X_HEIGHT", 0, scaledY }, 139a96d7823Smrg { "ITALIC_ANGLE", 0, unscaled }, 140a96d7823Smrg { "RELATIVE_SETWIDTH", 0, unscaled }, 141a96d7823Smrg { "RELATIVE_WEIGHT", 0, unscaled }, 142a96d7823Smrg { "WEIGHT", 0, unscaled }, 143a96d7823Smrg { "DESTINATION", 0, unscaled }, 144a96d7823Smrg { "PCL_FONT_NAME", 0, unscaled }, 145a96d7823Smrg { "_ADOBE_POSTSCRIPT_FONTNAME", 0, unscaled } 146a96d7823Smrg}; 147a96d7823Smrg 148a96d7823Smrgstatic fontProp rawFontPropTable[] = { 149a96d7823Smrg { "RAW_MIN_SPACE", 0, }, 150a96d7823Smrg { "RAW_NORM_SPACE", 0, }, 151a96d7823Smrg { "RAW_MAX_SPACE", 0, }, 152a96d7823Smrg { "RAW_END_SPACE", 0, }, 153a96d7823Smrg { "RAW_AVG_CAPITAL_WIDTH", 0, }, 154a96d7823Smrg { "RAW_AVG_LOWERCASE_WIDTH", 0, }, 155a96d7823Smrg { "RAW_QUAD_WIDTH", 0, }, 156a96d7823Smrg { "RAW_FIGURE_WIDTH", 0, }, 157a96d7823Smrg { "RAW_SUPERSCRIPT_X", 0, }, 158a96d7823Smrg { "RAW_SUPERSCRIPT_Y", 0, }, 159a96d7823Smrg { "RAW_SUBSCRIPT_X", 0, }, 160a96d7823Smrg { "RAW_SUBSCRIPT_Y", 0, }, 161a96d7823Smrg { "RAW_SUPERSCRIPT_SIZE", 0, }, 162a96d7823Smrg { "RAW_SUBSCRIPT_SIZE", 0, }, 163a96d7823Smrg { "RAW_SMALL_CAP_SIZE", 0, }, 164a96d7823Smrg { "RAW_UNDERLINE_POSITION", 0, }, 165a96d7823Smrg { "RAW_UNDERLINE_THICKNESS", 0, }, 166a96d7823Smrg { "RAW_STRIKEOUT_ASCENT", 0, }, 167a96d7823Smrg { "RAW_STRIKEOUT_DESCENT", 0, }, 168a96d7823Smrg { "RAW_CAP_HEIGHT", 0, }, 169a96d7823Smrg { "RAW_X_HEIGHT", 0, } 170a96d7823Smrg}; 171a96d7823Smrg 172a96d7823Smrgstatic void 173a96d7823SmrginitFontPropTable(void) 174a96d7823Smrg{ 175a96d7823Smrg int i; 176a96d7823Smrg fontProp *t; 177a96d7823Smrg 178a96d7823Smrg i = sizeof(fontNamePropTable) / sizeof(fontProp); 179a96d7823Smrg for (t = fontNamePropTable; i; i--, t++) 180a96d7823Smrg t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); 181a96d7823Smrg 182a96d7823Smrg i = sizeof(fontPropTable) / sizeof(fontProp); 183a96d7823Smrg for (t = fontPropTable; i; i--, t++) 184a96d7823Smrg t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); 185a96d7823Smrg 186a96d7823Smrg i = sizeof(rawFontPropTable) / sizeof(fontProp); 187a96d7823Smrg for (t = rawFontPropTable; i; i--, t++) 188a96d7823Smrg t->atom = MakeAtom(t->name, (unsigned) strlen(t->name), TRUE); 189a96d7823Smrg} 190a96d7823Smrg 191a96d7823Smrg#if 0 192a96d7823Smrgstatic FontEntryPtr 193a96d7823SmrgGetScalableEntry (FontPathElementPtr fpe, FontNamePtr name) 194a96d7823Smrg{ 195a96d7823Smrg FontDirectoryPtr dir; 196a96d7823Smrg 197a96d7823Smrg dir = (FontDirectoryPtr) fpe->private; 198a96d7823Smrg return FontFileFindNameInDir (&dir->scalable, name); 199a96d7823Smrg} 200a96d7823Smrg#endif 201a96d7823Smrg 202a96d7823Smrgstatic double 203a96d7823Smrgget_matrix_horizontal_component(double *matrix) 204a96d7823Smrg{ 205a96d7823Smrg return hypot(matrix[0], matrix[1]); 206a96d7823Smrg} 207a96d7823Smrg 208a96d7823Smrgstatic double 209a96d7823Smrgget_matrix_vertical_component(double *matrix) 210a96d7823Smrg{ 211a96d7823Smrg return hypot(matrix[2], matrix[3]); 212a96d7823Smrg} 213a96d7823Smrg 214a96d7823Smrg 215a96d7823Smrgstatic Bool 216a96d7823SmrgComputeScaleFactors(FontScalablePtr from, FontScalablePtr to, 217a96d7823Smrg double *dx, double *dy, double *sdx, double *sdy, 218a96d7823Smrg double *rescale_x) 219a96d7823Smrg{ 220a96d7823Smrg double srcpixelset, destpixelset, srcpixel, destpixel; 221a96d7823Smrg 222a96d7823Smrg srcpixelset = get_matrix_horizontal_component(from->pixel_matrix); 223a96d7823Smrg destpixelset = get_matrix_horizontal_component(to->pixel_matrix); 224a96d7823Smrg srcpixel = get_matrix_vertical_component(from->pixel_matrix); 225a96d7823Smrg destpixel = get_matrix_vertical_component(to->pixel_matrix); 226a96d7823Smrg 227a96d7823Smrg if (srcpixelset >= EPS) 228a96d7823Smrg { 229a96d7823Smrg *dx = destpixelset / srcpixelset; 230a96d7823Smrg *sdx = 1000.0 / srcpixelset; 231a96d7823Smrg } 232a96d7823Smrg else 233a96d7823Smrg *sdx = *dx = 0; 234a96d7823Smrg 235a96d7823Smrg *rescale_x = 1.0; 236a96d7823Smrg 237a96d7823Smrg /* If client specified a width, it overrides setsize; in this 238a96d7823Smrg context, we interpret width as applying to the font before any 239a96d7823Smrg rotation, even though that's not what is ultimately returned in 240a96d7823Smrg the width field. */ 241a96d7823Smrg if (from->width > 0 && to->width > 0 && fabs(*dx) > EPS) 242a96d7823Smrg { 243a96d7823Smrg double rescale = (double)to->width / (double)from->width; 244a96d7823Smrg 245a96d7823Smrg /* If the client specified a transformation matrix, the rescaling 246a96d7823Smrg for width does *not* override the setsize. Instead, just check 247a96d7823Smrg for consistency between the setsize from the matrix and the 248a96d7823Smrg setsize that would result from rescaling according to the width. 249a96d7823Smrg This assumes (perhaps naively) that the width is correctly 250a96d7823Smrg reported in the name. As an interesting side effect, this test 251a96d7823Smrg may result in choosing a different source bitmap (one that 252a96d7823Smrg scales consistently between the setsize *and* the width) than it 253a96d7823Smrg would choose if a width were not specified. Sort of a hidden 254a96d7823Smrg multiple-master functionality. */ 255a96d7823Smrg if ((to->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY || 256a96d7823Smrg (to->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) 257a96d7823Smrg { 258a96d7823Smrg /* Reject if resulting width difference is >= 1 pixel */ 259a96d7823Smrg if (fabs(rescale * from->width - *dx * from->width) >= 10) 260a96d7823Smrg return FALSE; 261a96d7823Smrg } 262a96d7823Smrg else 263a96d7823Smrg { 264a96d7823Smrg *rescale_x = rescale/(*dx); 265a96d7823Smrg *dx = rescale; 266a96d7823Smrg } 267a96d7823Smrg } 268a96d7823Smrg 269a96d7823Smrg if (srcpixel >= EPS) 270a96d7823Smrg { 271a96d7823Smrg *dy = destpixel / srcpixel; 272a96d7823Smrg *sdy = 1000.0 / srcpixel; 273a96d7823Smrg } 274a96d7823Smrg else 275a96d7823Smrg *sdy = *dy = 0; 276a96d7823Smrg 277a96d7823Smrg return TRUE; 278a96d7823Smrg} 279a96d7823Smrg 280a96d7823Smrg/* favor enlargement over reduction because of aliasing resulting 281a96d7823Smrg from reduction */ 282a96d7823Smrg#define SCORE(m,s) \ 283a96d7823Smrgif (m >= 1.0) { \ 284a96d7823Smrg if (m == 1.0) \ 285a96d7823Smrg score += (16 * s); \ 286a96d7823Smrg else if (m == 2.0) \ 287a96d7823Smrg score += (4 * s); \ 288a96d7823Smrg else \ 289a96d7823Smrg score += (int)(((double)(3 * s)) / m); \ 290a96d7823Smrg} else { \ 291a96d7823Smrg score += (int)(((double)(2 * s)) * m); \ 292a96d7823Smrg} 293a96d7823Smrg 294a96d7823Smrg/* don't need to favor enlargement when looking for bitmap that can 295a96d7823Smrg be used unscalable */ 296a96d7823Smrg#define SCORE2(m,s) \ 297a96d7823Smrgif (m >= 1.0) \ 298a96d7823Smrg score += (int)(((double)(8 * s)) / m); \ 299a96d7823Smrgelse \ 300a96d7823Smrg score += (int)(((double)(8 * s)) * m); 301a96d7823Smrg 302a96d7823Smrgstatic FontEntryPtr 303a96d7823SmrgFindBestToScale(FontPathElementPtr fpe, FontEntryPtr entry, 304a96d7823Smrg FontScalablePtr vals, FontScalablePtr best, 305a96d7823Smrg double *dxp, double *dyp, 306a96d7823Smrg double *sdxp, double *sdyp, 307a96d7823Smrg FontPathElementPtr *fpep) 308a96d7823Smrg{ 309a96d7823Smrg FontScalableRec temp; 310a96d7823Smrg int source, i; 311a96d7823Smrg int best_score, best_unscaled_score, 312a96d7823Smrg score; 313a96d7823Smrg double dx = 0.0, sdx = 0.0, dx_amount = 0.0, 314a96d7823Smrg dy = 0.0, sdy = 0.0, dy_amount = 0.0, 315a96d7823Smrg best_dx = 0.0, best_sdx = 0.0, best_dx_amount = 0.0, 316a96d7823Smrg best_dy = 0.0, best_sdy = 0.0, best_dy_amount = 0.0, 317a96d7823Smrg best_unscaled_sdx = 0.0, best_unscaled_sdy = 0.0, 318a96d7823Smrg rescale_x = 0.0, best_rescale_x = 0.0, 319a96d7823Smrg best_unscaled_rescale_x = 0.0; 320a96d7823Smrg FontEntryPtr zero; 321a96d7823Smrg FontNameRec zeroName; 322a96d7823Smrg char zeroChars[MAXFONTNAMELEN]; 323a96d7823Smrg FontDirectoryPtr dir; 324a96d7823Smrg FontScaledPtr scaled; 325a96d7823Smrg FontScalableExtraPtr extra; 326a96d7823Smrg FontScaledPtr best_scaled, best_unscaled; 327a96d7823Smrg FontPathElementPtr best_fpe = NULL, best_unscaled_fpe = NULL; 328a96d7823Smrg FontEntryPtr bitmap = NULL; 329a96d7823Smrg FontEntryPtr result; 330a96d7823Smrg int aliascount = 20; 331a96d7823Smrg FontPathElementPtr bitmap_fpe = NULL; 332a96d7823Smrg FontNameRec xlfdName; 333a96d7823Smrg 334a96d7823Smrg /* find the best match */ 335a96d7823Smrg rescale_x = 1.0; 336a96d7823Smrg best_scaled = 0; 337a96d7823Smrg best_score = 0; 338a96d7823Smrg best_unscaled = 0; 339a96d7823Smrg best_unscaled_score = -1; 340a96d7823Smrg best_dx_amount = best_dy_amount = HUGE_VAL; 341a96d7823Smrg memcpy (zeroChars, entry->name.name, entry->name.length); 342a96d7823Smrg zeroChars[entry->name.length] = '\0'; 343a96d7823Smrg zeroName.name = zeroChars; 344a96d7823Smrg FontParseXLFDName (zeroChars, &temp, FONT_XLFD_REPLACE_ZERO); 345a96d7823Smrg zeroName.length = strlen (zeroChars); 346a96d7823Smrg zeroName.ndashes = entry->name.ndashes; 347a96d7823Smrg xlfdName.name = vals->xlfdName; 348a96d7823Smrg xlfdName.length = strlen(xlfdName.name); 349a96d7823Smrg xlfdName.ndashes = FontFileCountDashes(xlfdName.name, xlfdName.length); 350a96d7823Smrg restart_bestscale_loop: ; 351a96d7823Smrg /* 352a96d7823Smrg * Look through all the registered bitmap sources for 353a96d7823Smrg * the same zero name as ours; entries along that one 354a96d7823Smrg * can be scaled as desired. 355a96d7823Smrg */ 356a96d7823Smrg for (source = 0; source < FontFileBitmapSources.count; source++) 357a96d7823Smrg { 358a96d7823Smrg /* There might already be a bitmap that satisfies the request 359a96d7823Smrg but didn't have a zero name that was found by the scalable 360a96d7823Smrg font matching logic. Keep track if there is. */ 361a96d7823Smrg if (bitmap == NULL && vals->xlfdName != NULL) 362a96d7823Smrg { 363a96d7823Smrg bitmap_fpe = FontFileBitmapSources.fpe[source]; 364a96d7823Smrg dir = (FontDirectoryPtr) bitmap_fpe->private; 365a96d7823Smrg bitmap = FontFileFindNameInDir (&dir->nonScalable, &xlfdName); 366a96d7823Smrg if (bitmap && bitmap->type != FONT_ENTRY_BITMAP) 367a96d7823Smrg { 368a96d7823Smrg if (bitmap->type == FONT_ENTRY_ALIAS && aliascount > 0) 369a96d7823Smrg { 370a96d7823Smrg aliascount--; 371a96d7823Smrg xlfdName.name = bitmap->u.alias.resolved; 372a96d7823Smrg xlfdName.length = strlen(xlfdName.name); 373a96d7823Smrg xlfdName.ndashes = FontFileCountDashes(xlfdName.name, 374a96d7823Smrg xlfdName.length); 375a96d7823Smrg bitmap = NULL; 376a96d7823Smrg goto restart_bestscale_loop; 377a96d7823Smrg } 378a96d7823Smrg else 379a96d7823Smrg bitmap = NULL; 380a96d7823Smrg } 381a96d7823Smrg } 382a96d7823Smrg 383a96d7823Smrg if (FontFileBitmapSources.fpe[source] == fpe) 384a96d7823Smrg zero = entry; 385a96d7823Smrg else 386a96d7823Smrg { 387a96d7823Smrg dir = (FontDirectoryPtr) FontFileBitmapSources.fpe[source]->private; 388a96d7823Smrg zero = FontFileFindNameInDir (&dir->scalable, &zeroName); 389a96d7823Smrg if (!zero) 390a96d7823Smrg continue; 391a96d7823Smrg } 392a96d7823Smrg extra = zero->u.scalable.extra; 393a96d7823Smrg for (i = 0; i < extra->numScaled; i++) 394a96d7823Smrg { 395a96d7823Smrg scaled = &extra->scaled[i]; 396a96d7823Smrg if (!scaled->bitmap) 397a96d7823Smrg continue; 398a96d7823Smrg if (!ComputeScaleFactors(&scaled->vals, vals, &dx, &dy, &sdx, &sdy, 399a96d7823Smrg &rescale_x)) 400a96d7823Smrg continue; 401a96d7823Smrg score = 0; 402a96d7823Smrg dx_amount = dx; 403a96d7823Smrg dy_amount = dy; 404a96d7823Smrg SCORE(dy_amount, 10); 405a96d7823Smrg SCORE(dx_amount, 1); 406a96d7823Smrg if ((score > best_score) || 407a96d7823Smrg ((score == best_score) && 408a96d7823Smrg ((dy_amount < best_dy_amount) || 409a96d7823Smrg ((dy_amount == best_dy_amount) && 410a96d7823Smrg (dx_amount < best_dx_amount))))) 411a96d7823Smrg { 412a96d7823Smrg best_fpe = FontFileBitmapSources.fpe[source]; 413a96d7823Smrg best_scaled = scaled; 414a96d7823Smrg best_score = score; 415a96d7823Smrg best_dx = dx; 416a96d7823Smrg best_dy = dy; 417a96d7823Smrg best_sdx = sdx; 418a96d7823Smrg best_sdy = sdy; 419a96d7823Smrg best_dx_amount = dx_amount; 420a96d7823Smrg best_dy_amount = dy_amount; 421a96d7823Smrg best_rescale_x = rescale_x; 422a96d7823Smrg } 423a96d7823Smrg /* Is this font a candidate for use without ugly rescaling? */ 424a96d7823Smrg if (fabs(dx) > EPS && fabs(dy) > EPS && 425a96d7823Smrg fabs(vals->pixel_matrix[0] * rescale_x - 426a96d7823Smrg scaled->vals.pixel_matrix[0]) < 1 && 427a96d7823Smrg fabs(vals->pixel_matrix[1] * rescale_x - 428a96d7823Smrg scaled->vals.pixel_matrix[1]) < EPS && 429a96d7823Smrg fabs(vals->pixel_matrix[2] - 430a96d7823Smrg scaled->vals.pixel_matrix[2]) < EPS && 431a96d7823Smrg fabs(vals->pixel_matrix[3] - 432a96d7823Smrg scaled->vals.pixel_matrix[3]) < 1) 433a96d7823Smrg { 434a96d7823Smrg /* Yes. The pixel sizes are close on the diagonal and 435a96d7823Smrg extremely close off the diagonal. */ 436a96d7823Smrg score = 0; 437a96d7823Smrg SCORE2(vals->pixel_matrix[3] / 438a96d7823Smrg scaled->vals.pixel_matrix[3], 10); 439a96d7823Smrg SCORE2(vals->pixel_matrix[0] * rescale_x / 440a96d7823Smrg scaled->vals.pixel_matrix[0], 1); 441a96d7823Smrg if (score > best_unscaled_score) 442a96d7823Smrg { 443a96d7823Smrg best_unscaled_fpe = FontFileBitmapSources.fpe[source]; 444a96d7823Smrg best_unscaled = scaled; 445a96d7823Smrg best_unscaled_sdx = sdx / dx; 446a96d7823Smrg best_unscaled_sdy = sdy / dy; 447a96d7823Smrg best_unscaled_score = score; 448a96d7823Smrg best_unscaled_rescale_x = rescale_x; 449a96d7823Smrg } 450a96d7823Smrg } 451a96d7823Smrg } 452a96d7823Smrg } 453a96d7823Smrg if (best_unscaled) 454a96d7823Smrg { 455a96d7823Smrg *best = best_unscaled->vals; 456a96d7823Smrg *fpep = best_unscaled_fpe; 457a96d7823Smrg *dxp = 1.0; 458a96d7823Smrg *dyp = 1.0; 459a96d7823Smrg *sdxp = best_unscaled_sdx; 460a96d7823Smrg *sdyp = best_unscaled_sdy; 461a96d7823Smrg rescale_x = best_unscaled_rescale_x; 462a96d7823Smrg result = best_unscaled->bitmap; 463a96d7823Smrg } 464a96d7823Smrg else if (best_scaled) 465a96d7823Smrg { 466a96d7823Smrg *best = best_scaled->vals; 467a96d7823Smrg *fpep = best_fpe; 468a96d7823Smrg *dxp = best_dx; 469a96d7823Smrg *dyp = best_dy; 470a96d7823Smrg *sdxp = best_sdx; 471a96d7823Smrg *sdyp = best_sdy; 472a96d7823Smrg rescale_x = best_rescale_x; 473a96d7823Smrg result = best_scaled->bitmap; 474a96d7823Smrg } 475a96d7823Smrg else 476a96d7823Smrg result = NULL; 477a96d7823Smrg 478a96d7823Smrg if (bitmap != NULL && (result == NULL || *dxp != 1.0 || *dyp != 1.0)) 479a96d7823Smrg { 480a96d7823Smrg *fpep = bitmap_fpe; 481a96d7823Smrg FontParseXLFDName (bitmap->name.name, best, FONT_XLFD_REPLACE_NONE); 482a96d7823Smrg if (ComputeScaleFactors(best, best, dxp, dyp, sdxp, sdyp, &rescale_x)) 483a96d7823Smrg result = bitmap; 484a96d7823Smrg else 485a96d7823Smrg result = NULL; 486a96d7823Smrg } 487a96d7823Smrg 488a96d7823Smrg if (result && rescale_x != 1.0) 489a96d7823Smrg { 490a96d7823Smrg /* We have rescaled horizontally due to an XLFD width field. Change 491a96d7823Smrg the matrix appropriately */ 492a96d7823Smrg vals->pixel_matrix[0] *= rescale_x; 493a96d7823Smrg vals->pixel_matrix[1] *= rescale_x; 494a96d7823Smrg vals->values_supplied = vals->values_supplied & ~POINTSIZE_MASK; 495a96d7823Smrg /* Recompute and reround the FontScalablePtr values after 496a96d7823Smrg rescaling for the new width. */ 497a96d7823Smrg FontFileCompleteXLFD(vals, vals); 498a96d7823Smrg } 499a96d7823Smrg 500a96d7823Smrg return result; 501a96d7823Smrg} 502a96d7823Smrg 503a96d7823Smrgstatic long 504a96d7823Smrgdoround(double x) 505a96d7823Smrg{ 506a96d7823Smrg return (x >= 0) ? (long)(x + .5) : (long)(x - .5); 507a96d7823Smrg} 508a96d7823Smrg 509a96d7823Smrgstatic int 510a96d7823SmrgcomputeProps(FontPropPtr pf, char *wasStringProp, 511a96d7823Smrg FontPropPtr npf, char *isStringProp, 512a96d7823Smrg unsigned int nprops, double xfactor, double yfactor, 513a96d7823Smrg double sXfactor, double sYfactor) 514a96d7823Smrg{ 515a96d7823Smrg int n; 516a96d7823Smrg int count; 517a96d7823Smrg fontProp *t; 518a96d7823Smrg double rawfactor = 0.0; 519a96d7823Smrg 520a96d7823Smrg for (count = 0; nprops > 0; nprops--, pf++, wasStringProp++) { 521a96d7823Smrg n = sizeof(fontPropTable) / sizeof(fontProp); 522a96d7823Smrg for (t = fontPropTable; n && (t->atom != pf->name); n--, t++); 523a96d7823Smrg if (!n) 524a96d7823Smrg continue; 525a96d7823Smrg 526a96d7823Smrg switch (t->type) { 527a96d7823Smrg case scaledX: 528a96d7823Smrg npf->value = doround(xfactor * (double)pf->value); 529a96d7823Smrg rawfactor = sXfactor; 530a96d7823Smrg break; 531a96d7823Smrg case scaledY: 532a96d7823Smrg npf->value = doround(yfactor * (double)pf->value); 533a96d7823Smrg rawfactor = sYfactor; 534a96d7823Smrg break; 535a96d7823Smrg case unscaled: 536a96d7823Smrg npf->value = pf->value; 537a96d7823Smrg npf->name = pf->name; 538a96d7823Smrg npf++; 539a96d7823Smrg count++; 540a96d7823Smrg *isStringProp++ = *wasStringProp; 541a96d7823Smrg break; 542a96d7823Smrg default: 543a96d7823Smrg break; 544a96d7823Smrg } 545a96d7823Smrg if (t->type != unscaled) 546a96d7823Smrg { 547a96d7823Smrg npf->name = pf->name; 548a96d7823Smrg npf++; 549a96d7823Smrg count++; 550a96d7823Smrg npf->value = doround(rawfactor * (double)pf->value); 551a96d7823Smrg npf->name = rawFontPropTable[t - fontPropTable].atom; 552a96d7823Smrg npf++; 553a96d7823Smrg count++; 554a96d7823Smrg *isStringProp++ = *wasStringProp; 555a96d7823Smrg *isStringProp++ = *wasStringProp; 556a96d7823Smrg } 557a96d7823Smrg } 558a96d7823Smrg return count; 559a96d7823Smrg} 560a96d7823Smrg 561a96d7823Smrg 562a96d7823Smrgstatic int 563a96d7823SmrgComputeScaledProperties(FontInfoPtr sourceFontInfo, /* the font to be scaled */ 564a96d7823Smrg char *name, /* name of resulting font */ 565a96d7823Smrg FontScalablePtr vals, 566a96d7823Smrg double dx, double dy, /* scale factors in x and y */ 567a96d7823Smrg double sdx, double sdy, /* directions */ 568a96d7823Smrg long sWidth, /* 1000-pixel average width */ 569a96d7823Smrg FontPropPtr *pProps, /* returns properties; 570a96d7823Smrg preallocated */ 571a96d7823Smrg char **pIsStringProp) /* return booleans; 572a96d7823Smrg preallocated */ 573a96d7823Smrg{ 574a96d7823Smrg int n; 575a96d7823Smrg char *ptr1 = NULL, *ptr2 = NULL; 576a96d7823Smrg char *ptr3; 577a96d7823Smrg FontPropPtr fp; 578a96d7823Smrg fontProp *fpt; 579a96d7823Smrg char *isStringProp; 580a96d7823Smrg int nProps; 581a96d7823Smrg 582a96d7823Smrg if (bitscaleGeneration != __GetServerGeneration()) { 583a96d7823Smrg initFontPropTable(); 584a96d7823Smrg bitscaleGeneration = __GetServerGeneration(); 585a96d7823Smrg } 586a96d7823Smrg nProps = NPROPS + 1 + sizeof(fontPropTable) / sizeof(fontProp) + 587a96d7823Smrg sizeof(rawFontPropTable) / sizeof(fontProp); 588a96d7823Smrg fp = malloc(sizeof(FontPropRec) * nProps); 589a96d7823Smrg *pProps = fp; 590a96d7823Smrg if (!fp) { 591a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate font properties (%ld*%d)\n", 592a96d7823Smrg (unsigned long)sizeof(FontPropRec), nProps); 593a96d7823Smrg return 1; 594a96d7823Smrg } 595a96d7823Smrg isStringProp = malloc (nProps); 596a96d7823Smrg *pIsStringProp = isStringProp; 597a96d7823Smrg if (!isStringProp) 598a96d7823Smrg { 599a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate isStringProp (%d)\n", nProps); 600a96d7823Smrg free (fp); 601a96d7823Smrg return 1; 602a96d7823Smrg } 603a96d7823Smrg ptr2 = name; 604a96d7823Smrg for (fpt = fontNamePropTable, n = NPROPS; 605a96d7823Smrg n; 606a96d7823Smrg fp++, fpt++, n--, isStringProp++) 607a96d7823Smrg { 608a96d7823Smrg 609a96d7823Smrg if (*ptr2) 610a96d7823Smrg { 611a96d7823Smrg ptr1 = ptr2 + 1; 612a96d7823Smrg if (!(ptr2 = strchr(ptr1, '-'))) ptr2 = strchr(ptr1, '\0'); 613a96d7823Smrg } 614a96d7823Smrg 615a96d7823Smrg *isStringProp = 0; 616a96d7823Smrg switch (fpt->type) { 617a96d7823Smrg case atom: 618a96d7823Smrg fp->value = MakeAtom(ptr1, ptr2 - ptr1, TRUE); 619a96d7823Smrg *isStringProp = 1; 620a96d7823Smrg break; 621a96d7823Smrg case truncate_atom: 622a96d7823Smrg for (ptr3 = ptr1; *ptr3; ptr3++) 623a96d7823Smrg if (*ptr3 == '[') 624a96d7823Smrg break; 625a96d7823Smrg if (!*ptr3) ptr3 = ptr2; 626a96d7823Smrg fp->value = MakeAtom(ptr1, ptr3 - ptr1, TRUE); 627a96d7823Smrg *isStringProp = 1; 628a96d7823Smrg break; 629a96d7823Smrg case pixel_size: 630a96d7823Smrg fp->value = doround(vals->pixel_matrix[3]); 631a96d7823Smrg break; 632a96d7823Smrg case point_size: 633a96d7823Smrg fp->value = doround(vals->point_matrix[3] * 10.0); 634a96d7823Smrg break; 635a96d7823Smrg case resolution_x: 636a96d7823Smrg fp->value = vals->x; 637a96d7823Smrg break; 638a96d7823Smrg case resolution_y: 639a96d7823Smrg fp->value = vals->y; 640a96d7823Smrg break; 641a96d7823Smrg case average_width: 642a96d7823Smrg fp->value = vals->width; 643a96d7823Smrg break; 644a96d7823Smrg case fontname: 645a96d7823Smrg fp->value = MakeAtom(name, strlen(name), TRUE); 646a96d7823Smrg *isStringProp = 1; 647a96d7823Smrg break; 648a96d7823Smrg case raw_ascent: 649a96d7823Smrg fp->value = sourceFontInfo->fontAscent * sdy; 650a96d7823Smrg break; 651a96d7823Smrg case raw_descent: 652a96d7823Smrg fp->value = sourceFontInfo->fontDescent * sdy; 653a96d7823Smrg break; 654a96d7823Smrg case raw_pointsize: 655a96d7823Smrg fp->value = (long)(72270.0 / (double)vals->y + .5); 656a96d7823Smrg break; 657a96d7823Smrg case raw_pixelsize: 658a96d7823Smrg fp->value = 1000; 659a96d7823Smrg break; 660a96d7823Smrg case raw_average_width: 661a96d7823Smrg fp->value = sWidth; 662a96d7823Smrg break; 663a96d7823Smrg default: 664a96d7823Smrg break; 665a96d7823Smrg } 666a96d7823Smrg fp->name = fpt->atom; 667a96d7823Smrg } 668a96d7823Smrg n = NPROPS; 669a96d7823Smrg n += computeProps(sourceFontInfo->props, sourceFontInfo->isStringProp, 670a96d7823Smrg fp, isStringProp, sourceFontInfo->nprops, dx, dy, 671a96d7823Smrg sdx, sdy); 672a96d7823Smrg return n; 673a96d7823Smrg} 674a96d7823Smrg 675a96d7823Smrg 676a96d7823Smrgstatic int 677a96d7823Smrgcompute_xform_matrix(FontScalablePtr vals, double dx, double dy, 678a96d7823Smrg double *xform, double *inv_xform, 679a96d7823Smrg double *xmult, double *ymult) 680a96d7823Smrg{ 681a96d7823Smrg double det; 682a96d7823Smrg double pixel = get_matrix_vertical_component(vals->pixel_matrix); 683a96d7823Smrg double pixelset = get_matrix_horizontal_component(vals->pixel_matrix); 684a96d7823Smrg 685a96d7823Smrg if (pixel < EPS || pixelset < EPS) return 0; 686a96d7823Smrg 687a96d7823Smrg /* Initialize the transformation matrix to the scaling factors */ 688a96d7823Smrg xform[0] = dx / pixelset; 689a96d7823Smrg xform[1] = xform[2] = 0.0; 690a96d7823Smrg xform[3] = dy / pixel; 691a96d7823Smrg 692a96d7823Smrg/* Inline matrix multiply -- somewhat ugly to minimize register usage */ 693a96d7823Smrg#define MULTIPLY_XFORM(a,b,c,d) \ 694a96d7823Smrg{ \ 695a96d7823Smrg register double aa = (a), bb = (b), cc = (c), dd = (d); \ 696a96d7823Smrg register double temp; \ 697a96d7823Smrg temp = aa * xform[0] + cc * xform[1]; \ 698a96d7823Smrg aa = aa * xform[2] + cc * xform[3]; \ 699a96d7823Smrg xform[1] = bb * xform[0] + dd * xform[1]; \ 700a96d7823Smrg xform[3] = bb * xform[2] + dd * xform[3]; \ 701a96d7823Smrg xform[0] = temp; \ 702a96d7823Smrg xform[2] = aa; \ 703a96d7823Smrg} 704a96d7823Smrg 705a96d7823Smrg /* Rescale the transformation matrix for size of source font */ 706a96d7823Smrg MULTIPLY_XFORM(vals->pixel_matrix[0], 707a96d7823Smrg vals->pixel_matrix[1], 708a96d7823Smrg vals->pixel_matrix[2], 709a96d7823Smrg vals->pixel_matrix[3]); 710a96d7823Smrg 711a96d7823Smrg *xmult = xform[0]; 712a96d7823Smrg *ymult = xform[3]; 713a96d7823Smrg 714a96d7823Smrg 715a96d7823Smrg if (inv_xform == NULL) return 1; 716a96d7823Smrg 717a96d7823Smrg /* Compute the determinant for use in inverting the matrix. */ 718a96d7823Smrg det = xform[0] * xform[3] - xform[1] * xform[2]; 719a96d7823Smrg 720a96d7823Smrg /* If the determinant is tiny or zero, give up */ 721a96d7823Smrg if (fabs(det) < EPS) return 0; 722a96d7823Smrg 723a96d7823Smrg /* Compute the inverse */ 724a96d7823Smrg inv_xform[0] = xform[3] / det; 725a96d7823Smrg inv_xform[1] = -xform[1] / det; 726a96d7823Smrg inv_xform[2] = -xform[2] / det; 727a96d7823Smrg inv_xform[3] = xform[0] / det; 728a96d7823Smrg 729a96d7823Smrg return 1; 730a96d7823Smrg} 731a96d7823Smrg 732a96d7823Smrg/* 733a96d7823Smrg * ScaleFont 734a96d7823Smrg * returns a pointer to the new scaled font, or NULL (due to AllocError). 735a96d7823Smrg */ 736a96d7823Smrg#pragma GCC diagnostic ignored "-Wbad-function-cast" 737a96d7823Smrg 738a96d7823Smrgstatic FontPtr 739a96d7823SmrgScaleFont(FontPtr opf, /* originating font */ 740a96d7823Smrg double widthMult, /* glyphs width scale factor */ 741a96d7823Smrg double heightMult, /* glyphs height scale factor */ 742a96d7823Smrg double sWidthMult, /* scalable glyphs width scale factor */ 743a96d7823Smrg double sHeightMult, /* scalable glyphs height scale factor */ 744a96d7823Smrg FontScalablePtr vals, 745a96d7823Smrg double *newWidthMult, /* return: X component of glyphs width 746a96d7823Smrg scale factor */ 747a96d7823Smrg double *newHeightMult, /* return: Y component of glyphs height 748a96d7823Smrg scale factor */ 749a96d7823Smrg long *sWidth) /* return: average 1000-pixel width */ 750a96d7823Smrg{ 751a96d7823Smrg FontPtr pf; 752a96d7823Smrg FontInfoPtr pfi, 753a96d7823Smrg opfi; 754a96d7823Smrg BitmapFontPtr bitmapFont, 755a96d7823Smrg obitmapFont; 756a96d7823Smrg CharInfoPtr pci, 757a96d7823Smrg opci; 758a96d7823Smrg int nchars = 0; /* how many characters in the font */ 759a96d7823Smrg int i; 760a96d7823Smrg int firstCol, lastCol, firstRow, lastRow; 761a96d7823Smrg double xform[4], inv_xform[4]; 762a96d7823Smrg double xmult, ymult; 763a96d7823Smrg int totalwidth = 0, totalchars = 0; 764a96d7823Smrg#define OLDINDEX(i) (((i)/(lastCol - firstCol + 1) + \ 765a96d7823Smrg firstRow - opf->info.firstRow) * \ 766a96d7823Smrg (opf->info.lastCol - opf->info.firstCol + 1) + \ 767a96d7823Smrg (i)%(lastCol - firstCol + 1) + \ 768a96d7823Smrg firstCol - opf->info.firstCol) 769a96d7823Smrg 770a96d7823Smrg *sWidth = 0; 771a96d7823Smrg 772a96d7823Smrg opfi = &opf->info; 773a96d7823Smrg obitmapFont = (BitmapFontPtr) opf->fontPrivate; 774a96d7823Smrg 775a96d7823Smrg bitmapFont = 0; 776a96d7823Smrg if (!(pf = CreateFontRec())) { 777a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate FontRec (%ld)\n", 778a96d7823Smrg (unsigned long)sizeof(FontRec)); 779a96d7823Smrg goto bail; 780a96d7823Smrg } 781a96d7823Smrg pf->refcnt = 0; 782a96d7823Smrg pf->bit = opf->bit; 783a96d7823Smrg pf->byte = opf->byte; 784a96d7823Smrg pf->glyph = opf->glyph; 785a96d7823Smrg pf->scan = opf->scan; 786a96d7823Smrg 787a96d7823Smrg pf->get_glyphs = bitmapGetGlyphs; 788a96d7823Smrg pf->get_metrics = bitmapGetMetrics; 789a96d7823Smrg pf->unload_font = bitmapUnloadScalable; 790a96d7823Smrg pf->unload_glyphs = NULL; 791a96d7823Smrg 792a96d7823Smrg pfi = &pf->info; 793a96d7823Smrg *pfi = *opfi; 794a96d7823Smrg /* If charset subsetting specified in vals, determine what our range 795a96d7823Smrg needs to be for the output font */ 796a96d7823Smrg if (vals->nranges) 797a96d7823Smrg { 798a96d7823Smrg pfi->allExist = 0; 799a96d7823Smrg firstCol = 255; 800a96d7823Smrg lastCol = 0; 801a96d7823Smrg firstRow = 255; 802a96d7823Smrg lastRow = 0; 803a96d7823Smrg 804a96d7823Smrg for (i = 0; i < vals->nranges; i++) 805a96d7823Smrg { 806a96d7823Smrg if (vals->ranges[i].min_char_high != vals->ranges[i].max_char_high) 807a96d7823Smrg { 808a96d7823Smrg firstCol = opfi->firstCol; 809a96d7823Smrg lastCol = opfi->lastCol; 810a96d7823Smrg } 811a96d7823Smrg if (firstCol > vals->ranges[i].min_char_low) 812a96d7823Smrg firstCol = vals->ranges[i].min_char_low; 813a96d7823Smrg if (lastCol < vals->ranges[i].max_char_low) 814a96d7823Smrg lastCol = vals->ranges[i].max_char_low; 815a96d7823Smrg if (firstRow > vals->ranges[i].min_char_high) 816a96d7823Smrg firstRow = vals->ranges[i].min_char_high; 817a96d7823Smrg if (lastRow < vals->ranges[i].max_char_high) 818a96d7823Smrg lastRow = vals->ranges[i].max_char_high; 819a96d7823Smrg } 820a96d7823Smrg 821a96d7823Smrg if (firstCol > lastCol || firstRow > lastRow) 822a96d7823Smrg goto bail; 823a96d7823Smrg 824a96d7823Smrg if (firstCol < opfi->firstCol) 825a96d7823Smrg firstCol = opfi->firstCol; 826a96d7823Smrg if (lastCol > opfi->lastCol) 827a96d7823Smrg lastCol = opfi->lastCol; 828a96d7823Smrg if (firstRow < opfi->firstRow) 829a96d7823Smrg firstRow = opfi->firstRow; 830a96d7823Smrg if (lastRow > opfi->lastRow) 831a96d7823Smrg lastRow = opfi->lastRow; 832a96d7823Smrg } 833a96d7823Smrg else 834a96d7823Smrg { 835a96d7823Smrg firstCol = opfi->firstCol; 836a96d7823Smrg lastCol = opfi->lastCol; 837a96d7823Smrg firstRow = opfi->firstRow; 838a96d7823Smrg lastRow = opfi->lastRow; 839a96d7823Smrg } 840a96d7823Smrg 841a96d7823Smrg bitmapFont = malloc(sizeof(BitmapFontRec)); 842a96d7823Smrg if (!bitmapFont) { 843a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate bitmapFont (%ld)\n", 844a96d7823Smrg (unsigned long)sizeof(BitmapFontRec)); 845a96d7823Smrg goto bail; 846a96d7823Smrg } 847a96d7823Smrg nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); 848a96d7823Smrg pfi->firstRow = firstRow; 849a96d7823Smrg pfi->lastRow = lastRow; 850a96d7823Smrg pfi->firstCol = firstCol; 851a96d7823Smrg pfi->lastCol = lastCol; 852a96d7823Smrg pf->fontPrivate = (pointer) bitmapFont; 853a96d7823Smrg bitmapFont->version_num = obitmapFont->version_num; 854a96d7823Smrg bitmapFont->num_chars = nchars; 855a96d7823Smrg bitmapFont->num_tables = obitmapFont->num_tables; 856a96d7823Smrg bitmapFont->metrics = 0; 857a96d7823Smrg bitmapFont->ink_metrics = 0; 858a96d7823Smrg bitmapFont->bitmaps = 0; 859a96d7823Smrg bitmapFont->encoding = 0; 860a96d7823Smrg bitmapFont->bitmapExtra = 0; 861a96d7823Smrg bitmapFont->pDefault = 0; 862a96d7823Smrg bitmapFont->metrics = malloc(nchars * sizeof(CharInfoRec)); 863a96d7823Smrg if (!bitmapFont->metrics) { 864a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate metrics (%d*%ld)\n", 865a96d7823Smrg nchars, (unsigned long)sizeof(CharInfoRec)); 866a96d7823Smrg goto bail; 867a96d7823Smrg } 868a96d7823Smrg bitmapFont->encoding = calloc(NUM_SEGMENTS(nchars), sizeof(CharInfoPtr*)); 869a96d7823Smrg if (!bitmapFont->encoding) { 870a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate encoding (%d*%ld)\n", 871a96d7823Smrg nchars, (unsigned long)sizeof(CharInfoPtr)); 872a96d7823Smrg goto bail; 873a96d7823Smrg } 874a96d7823Smrg 875a96d7823Smrg#undef MAXSHORT 876a96d7823Smrg#define MAXSHORT 32767 877a96d7823Smrg#undef MINSHORT 878a96d7823Smrg#define MINSHORT -32768 879a96d7823Smrg 880a96d7823Smrg pfi->anamorphic = FALSE; 881a96d7823Smrg if (heightMult != widthMult) 882a96d7823Smrg pfi->anamorphic = TRUE; 883a96d7823Smrg pfi->cachable = TRUE; 884a96d7823Smrg 885a96d7823Smrg if (!compute_xform_matrix(vals, widthMult, heightMult, xform, 886a96d7823Smrg inv_xform, &xmult, &ymult)) 887a96d7823Smrg goto bail; 888a96d7823Smrg 889a96d7823Smrg pfi->fontAscent = opfi->fontAscent * ymult; 890a96d7823Smrg pfi->fontDescent = opfi->fontDescent * ymult; 891a96d7823Smrg 892a96d7823Smrg pfi->minbounds.leftSideBearing = MAXSHORT; 893a96d7823Smrg pfi->minbounds.rightSideBearing = MAXSHORT; 894a96d7823Smrg pfi->minbounds.ascent = MAXSHORT; 895a96d7823Smrg pfi->minbounds.descent = MAXSHORT; 896a96d7823Smrg pfi->minbounds.characterWidth = MAXSHORT; 897a96d7823Smrg pfi->minbounds.attributes = MAXSHORT; 898a96d7823Smrg 899a96d7823Smrg pfi->maxbounds.leftSideBearing = MINSHORT; 900a96d7823Smrg pfi->maxbounds.rightSideBearing = MINSHORT; 901a96d7823Smrg pfi->maxbounds.ascent = MINSHORT; 902a96d7823Smrg pfi->maxbounds.descent = MINSHORT; 903a96d7823Smrg pfi->maxbounds.characterWidth = MINSHORT; 904a96d7823Smrg pfi->maxbounds.attributes = MINSHORT; 905a96d7823Smrg 906a96d7823Smrg /* Compute the transformation and inverse transformation matrices. 907a96d7823Smrg Can fail if the determinant is zero. */ 908a96d7823Smrg 909a96d7823Smrg pci = bitmapFont->metrics; 910a96d7823Smrg for (i = 0; i < nchars; i++) 911a96d7823Smrg { 912a96d7823Smrg if ((opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i)))) 913a96d7823Smrg { 914a96d7823Smrg double newlsb, newrsb, newdesc, newasc, point[2]; 915a96d7823Smrg 916a96d7823Smrg#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8)) 917a96d7823Smrg#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8)) 918a96d7823Smrg 919a96d7823Smrg if (vals->nranges) 920a96d7823Smrg { 921a96d7823Smrg int row = i / (lastCol - firstCol + 1) + firstRow; 922a96d7823Smrg int col = i % (lastCol - firstCol + 1) + firstCol; 923a96d7823Smrg int ch = (row << 8) + col; 924a96d7823Smrg int j; 925a96d7823Smrg for (j = 0; j < vals->nranges; j++) 926a96d7823Smrg if (ch >= minchar(vals->ranges[j]) && 927a96d7823Smrg ch <= maxchar(vals->ranges[j])) 928a96d7823Smrg break; 929a96d7823Smrg if (j == vals->nranges) 930a96d7823Smrg { 931a96d7823Smrg continue; 932a96d7823Smrg } 933a96d7823Smrg } 934a96d7823Smrg 935a96d7823Smrg if (opci->metrics.leftSideBearing == 0 && 936a96d7823Smrg opci->metrics.rightSideBearing == 0 && 937a96d7823Smrg opci->metrics.ascent == 0 && 938a96d7823Smrg opci->metrics.descent == 0 && 939a96d7823Smrg opci->metrics.characterWidth == 0) 940a96d7823Smrg { 941a96d7823Smrg continue; 942a96d7823Smrg } 943a96d7823Smrg 944a96d7823Smrg if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) { 945a96d7823Smrg bitmapFont->encoding[SEGMENT_MAJOR(i)]= 946a96d7823Smrg calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr)); 947a96d7823Smrg if(!bitmapFont->encoding[SEGMENT_MAJOR(i)]) 948a96d7823Smrg goto bail; 949a96d7823Smrg } 950a96d7823Smrg ACCESSENCODINGL(bitmapFont->encoding, i) = pci; 951a96d7823Smrg 952a96d7823Smrg /* Compute new extents for this glyph */ 953a96d7823Smrg TRANSFORM_POINT(xform, 954a96d7823Smrg opci->metrics.leftSideBearing, 955a96d7823Smrg -opci->metrics.descent, 956a96d7823Smrg point); 957a96d7823Smrg newlsb = point[0]; 958a96d7823Smrg newrsb = newlsb; 959a96d7823Smrg newdesc = -point[1]; 960a96d7823Smrg newasc = -newdesc; 961a96d7823Smrg TRANSFORM_POINT(xform, 962a96d7823Smrg opci->metrics.leftSideBearing, 963a96d7823Smrg opci->metrics.ascent, 964a96d7823Smrg point); 965a96d7823Smrg CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); 966a96d7823Smrg TRANSFORM_POINT(xform, 967a96d7823Smrg opci->metrics.rightSideBearing, 968a96d7823Smrg -opci->metrics.descent, 969a96d7823Smrg point); 970a96d7823Smrg CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); 971a96d7823Smrg TRANSFORM_POINT(xform, 972a96d7823Smrg opci->metrics.rightSideBearing, 973a96d7823Smrg opci->metrics.ascent, 974a96d7823Smrg point); 975a96d7823Smrg CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); 976a96d7823Smrg 977a96d7823Smrg pci->metrics.leftSideBearing = (int)floor(newlsb); 978a96d7823Smrg pci->metrics.rightSideBearing = (int)floor(newrsb + .5); 979a96d7823Smrg pci->metrics.descent = (int)ceil(newdesc); 980a96d7823Smrg pci->metrics.ascent = (int)floor(newasc + .5); 981a96d7823Smrg /* Accumulate total width of characters before transformation, 982a96d7823Smrg to ascertain predominant direction of font. */ 983a96d7823Smrg totalwidth += opci->metrics.characterWidth; 984a96d7823Smrg pci->metrics.characterWidth = 985a96d7823Smrg doround((double)opci->metrics.characterWidth * xmult); 986a96d7823Smrg pci->metrics.attributes = 987a96d7823Smrg doround((double)opci->metrics.characterWidth * sWidthMult); 988a96d7823Smrg if (!pci->metrics.characterWidth) 989a96d7823Smrg { 990a96d7823Smrg /* Since transformation may shrink width, height, and 991a96d7823Smrg escapement to zero, make sure existing characters 992a96d7823Smrg are not mistaken for undefined characters. */ 993a96d7823Smrg 994a96d7823Smrg if (pci->metrics.rightSideBearing == 995a96d7823Smrg pci->metrics.leftSideBearing) 996a96d7823Smrg pci->metrics.rightSideBearing++; 997a96d7823Smrg if (pci->metrics.ascent == -pci->metrics.descent) 998a96d7823Smrg pci->metrics.ascent++; 999a96d7823Smrg } 1000a96d7823Smrg 1001a96d7823Smrg pci++; 1002a96d7823Smrg } 1003a96d7823Smrg } 1004a96d7823Smrg 1005a96d7823Smrg 1006a96d7823Smrg /* 1007a96d7823Smrg * For each character, set the per-character metrics, scale the glyph, and 1008a96d7823Smrg * check per-font minbounds and maxbounds character information. 1009a96d7823Smrg */ 1010a96d7823Smrg 1011a96d7823Smrg pci = bitmapFont->metrics; 1012a96d7823Smrg for (i = 0; i < nchars; i++) 1013a96d7823Smrg { 1014a96d7823Smrg if ((pci = ACCESSENCODING(bitmapFont->encoding,i)) && 1015a96d7823Smrg (opci = ACCESSENCODING(obitmapFont->encoding,OLDINDEX(i)))) 1016a96d7823Smrg { 1017a96d7823Smrg totalchars++; 1018a96d7823Smrg *sWidth += abs((int)(INT16)pci->metrics.attributes); 1019a96d7823Smrg#define MINMAX(field) \ 1020a96d7823Smrg if (pfi->minbounds.field > pci->metrics.field) \ 1021a96d7823Smrg pfi->minbounds.field = pci->metrics.field; \ 1022a96d7823Smrg if (pfi->maxbounds.field < pci->metrics.field) \ 1023a96d7823Smrg pfi->maxbounds.field = pci->metrics.field 1024a96d7823Smrg 1025a96d7823Smrg MINMAX(leftSideBearing); 1026a96d7823Smrg MINMAX(rightSideBearing); 1027a96d7823Smrg MINMAX(ascent); 1028a96d7823Smrg MINMAX(descent); 1029a96d7823Smrg MINMAX(characterWidth); 1030a96d7823Smrg 1031a96d7823Smrg /* Hack: Cast attributes into a signed quantity. Tread lightly 1032a96d7823Smrg for now and don't go changing the global Xproto.h file */ 1033a96d7823Smrg if ((INT16)pfi->minbounds.attributes > 1034a96d7823Smrg (INT16)pci->metrics.attributes) 1035a96d7823Smrg pfi->minbounds.attributes = pci->metrics.attributes; 1036a96d7823Smrg if ((INT16)pfi->maxbounds.attributes < 1037a96d7823Smrg (INT16)pci->metrics.attributes) 1038a96d7823Smrg pfi->maxbounds.attributes = pci->metrics.attributes; 1039a96d7823Smrg#undef MINMAX 1040a96d7823Smrg } 1041a96d7823Smrg } 1042a96d7823Smrg pfi->ink_minbounds = pfi->minbounds; 1043a96d7823Smrg pfi->ink_maxbounds = pfi->maxbounds; 1044a96d7823Smrg if (totalchars) 1045a96d7823Smrg { 1046a96d7823Smrg *sWidth = (*sWidth * 10 + totalchars / 2) / totalchars; 1047a96d7823Smrg if (totalwidth < 0) 1048a96d7823Smrg { 1049a96d7823Smrg /* Dominant direction is R->L */ 1050a96d7823Smrg *sWidth = -*sWidth; 1051a96d7823Smrg } 1052a96d7823Smrg 1053a96d7823Smrg if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth) 1054a96d7823Smrg vals->width = pfi->minbounds.characterWidth * 10; 1055a96d7823Smrg else 1056a96d7823Smrg vals->width = doround((double)*sWidth * vals->pixel_matrix[0] / 1057a96d7823Smrg 1000.0); 1058a96d7823Smrg } 1059a96d7823Smrg else 1060a96d7823Smrg { 1061a96d7823Smrg vals->width = 0; 1062a96d7823Smrg *sWidth = 0; 1063a96d7823Smrg } 1064a96d7823Smrg FontComputeInfoAccelerators (pfi); 1065a96d7823Smrg 1066a96d7823Smrg if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) { 1067a96d7823Smrg unsigned int r, 1068a96d7823Smrg c, 1069a96d7823Smrg cols; 1070a96d7823Smrg 1071a96d7823Smrg r = pfi->defaultCh >> 8; 1072a96d7823Smrg c = pfi->defaultCh & 0xFF; 1073a96d7823Smrg if (pfi->firstRow <= r && r <= pfi->lastRow && 1074a96d7823Smrg pfi->firstCol <= c && c <= pfi->lastCol) { 1075a96d7823Smrg cols = pfi->lastCol - pfi->firstCol + 1; 1076a96d7823Smrg r = r - pfi->firstRow; 1077a96d7823Smrg c = c - pfi->firstCol; 1078a96d7823Smrg bitmapFont->pDefault = 1079a96d7823Smrg ACCESSENCODING(bitmapFont->encoding, r * cols + c); 1080a96d7823Smrg } 1081a96d7823Smrg } 1082a96d7823Smrg 1083a96d7823Smrg *newWidthMult = xmult; 1084a96d7823Smrg *newHeightMult = ymult; 1085a96d7823Smrg return pf; 1086a96d7823Smrgbail: 1087a96d7823Smrg if (pf) 1088a96d7823Smrg free(pf); 1089a96d7823Smrg if (bitmapFont) { 1090a96d7823Smrg free(bitmapFont->metrics); 1091a96d7823Smrg free(bitmapFont->ink_metrics); 1092a96d7823Smrg free(bitmapFont->bitmaps); 1093a96d7823Smrg if(bitmapFont->encoding) 1094a96d7823Smrg for(i=0; i<NUM_SEGMENTS(nchars); i++) 1095a96d7823Smrg free(bitmapFont->encoding[i]); 1096a96d7823Smrg free(bitmapFont->encoding); 1097a96d7823Smrg } 1098a96d7823Smrg return NULL; 1099a96d7823Smrg} 1100a96d7823Smrg 1101a96d7823Smrgstatic void 1102a96d7823SmrgScaleBitmap(FontPtr pFont, CharInfoPtr opci, CharInfoPtr pci, 1103a96d7823Smrg double *inv_xform, double widthMult, double heightMult) 1104a96d7823Smrg{ 1105a96d7823Smrg register char *bitmap, /* The bits */ 1106a96d7823Smrg *newBitmap; 1107a96d7823Smrg register int bpr, /* Padding information */ 1108a96d7823Smrg newBpr; 1109a96d7823Smrg int width, /* Extents information */ 1110a96d7823Smrg height, 1111a96d7823Smrg newWidth, 1112a96d7823Smrg newHeight; 1113a96d7823Smrg register int row, /* Loop variables */ 1114a96d7823Smrg col; 1115a96d7823Smrg INT32 deltaX, /* Increments for resampling loop */ 1116a96d7823Smrg deltaY; 1117a96d7823Smrg INT32 xValue, /* Subscripts for resampling loop */ 1118a96d7823Smrg yValue; 1119a96d7823Smrg double point[2]; 1120a96d7823Smrg unsigned char *char_grayscale = 0; 1121a96d7823Smrg INT32 *diffusion_workspace = NULL, *thisrow = NULL, 1122a96d7823Smrg *nextrow = NULL, pixmult = 0; 1123a96d7823Smrg int box_x = 0, box_y = 0; 1124a96d7823Smrg 1125a96d7823Smrg static unsigned char masklsb[] = 1126a96d7823Smrg { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 }; 1127a96d7823Smrg static unsigned char maskmsb[] = 1128a96d7823Smrg { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; 1129a96d7823Smrg unsigned char *mask = (pFont->bit == LSBFirst ? masklsb : maskmsb); 1130a96d7823Smrg 1131a96d7823Smrg 1132a96d7823Smrg bitmap = opci->bits; 1133a96d7823Smrg newBitmap = pci->bits; 1134a96d7823Smrg width = GLYPHWIDTHPIXELS(opci); 1135a96d7823Smrg height = GLYPHHEIGHTPIXELS(opci); 1136a96d7823Smrg newWidth = GLYPHWIDTHPIXELS(pci); 1137a96d7823Smrg newHeight = GLYPHHEIGHTPIXELS(pci); 1138a96d7823Smrg if (!newWidth || !newHeight || !width || !height) 1139a96d7823Smrg return; 1140a96d7823Smrg 1141a96d7823Smrg bpr = BYTES_PER_ROW(width, pFont->glyph); 1142a96d7823Smrg newBpr = BYTES_PER_ROW(newWidth, pFont->glyph); 1143a96d7823Smrg 1144a96d7823Smrg if (widthMult > 0.0 && heightMult > 0.0 && 1145a96d7823Smrg (widthMult < 1.0 || heightMult < 1.0)) 1146a96d7823Smrg { 1147a96d7823Smrg /* We are reducing in one or both dimensions. In an attempt to 1148a96d7823Smrg reduce aliasing, we'll antialias by passing the original 1149a96d7823Smrg glyph through a low-pass box filter (which results in a 1150a96d7823Smrg grayscale image), then use error diffusion to create bitonal 1151a96d7823Smrg output in the resampling loop. */ 1152a96d7823Smrg 1153a96d7823Smrg /* First compute the sizes of the box filter */ 1154a96d7823Smrg widthMult = ceil(1.0 / widthMult); 1155a96d7823Smrg heightMult = ceil(1.0 / heightMult); 1156a96d7823Smrg box_x = width / 2; 1157a96d7823Smrg box_y = height / 2; 1158a96d7823Smrg if (widthMult < (double)box_x) box_x = (int)widthMult; 1159a96d7823Smrg if (heightMult < (double)box_y) box_y = (int)heightMult; 1160a96d7823Smrg /* The pixmult value (below) is used to darken the image before 1161a96d7823Smrg we perform error diffusion: a necessary concession to the 1162a96d7823Smrg fact that it's very difficult to generate readable halftoned 1163a96d7823Smrg glyphs. The degree of darkening is proportional to the size 1164a96d7823Smrg of the blurring filter, hence inversely proportional to the 1165a96d7823Smrg darkness of the lightest gray that results from antialiasing. 1166a96d7823Smrg The result is that characters that exercise this logic (those 1167a96d7823Smrg generated by reducing from a larger source font) tend to err 1168a96d7823Smrg on the side of being too bold instead of being too light to 1169a96d7823Smrg be readable. */ 1170a96d7823Smrg pixmult = box_x * box_y * 192; 1171a96d7823Smrg 1172a96d7823Smrg if (box_x > 1 || box_y > 1) 1173a96d7823Smrg { 1174a96d7823Smrg /* Looks like we need to anti-alias. Create a workspace to 1175a96d7823Smrg contain the grayscale character plus an additional row and 1176a96d7823Smrg column for scratch */ 1177a96d7823Smrg char_grayscale = malloc((width + 1) * (height + 1)); 1178a96d7823Smrg if (char_grayscale) 1179a96d7823Smrg { 1180a96d7823Smrg diffusion_workspace = calloc((newWidth + 2) * 2, sizeof(int)); 1181a96d7823Smrg if (!diffusion_workspace) 1182a96d7823Smrg { 1183a96d7823Smrg fprintf(stderr, "Warning: Couldn't allocate diffusion" 1184a96d7823Smrg " workspace (%ld)\n", 1185a96d7823Smrg (newWidth + 2) * 2 * (unsigned long)sizeof(int)); 1186a96d7823Smrg free(char_grayscale); 1187a96d7823Smrg char_grayscale = (unsigned char *)0; 1188a96d7823Smrg } 1189a96d7823Smrg /* Initialize our error diffusion workspace for later use */ 1190a96d7823Smrg thisrow = diffusion_workspace + 1; 1191a96d7823Smrg nextrow = diffusion_workspace + newWidth + 3; 1192a96d7823Smrg } else { 1193a96d7823Smrg fprintf(stderr, "Warning: Couldn't allocate character grayscale (%d)\n", (width + 1) * (height + 1)); 1194a96d7823Smrg } 1195a96d7823Smrg } 1196a96d7823Smrg } 1197a96d7823Smrg 1198a96d7823Smrg if (char_grayscale) 1199a96d7823Smrg { 1200a96d7823Smrg /* We will be doing antialiasing. First copy the bitmap into 1201a96d7823Smrg our buffer, mapping input range [0,1] to output range 1202a96d7823Smrg [0,255]. */ 1203a96d7823Smrg register unsigned char *srcptr, *dstptr; 1204a96d7823Smrg srcptr = (unsigned char *)bitmap; 1205a96d7823Smrg dstptr = char_grayscale; 1206a96d7823Smrg for (row = 0; row < height; row++) 1207a96d7823Smrg { 1208a96d7823Smrg for (col = 0; col < width; col++) 1209a96d7823Smrg *dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0; 1210a96d7823Smrg srcptr += bpr; /* On to next row of source */ 1211a96d7823Smrg dstptr++; /* Skip scratch column in dest */ 1212a96d7823Smrg } 1213a96d7823Smrg if (box_x > 1) 1214a96d7823Smrg { 1215a96d7823Smrg /* Our box filter has a width > 1... let's filter the rows */ 1216a96d7823Smrg 1217a96d7823Smrg int right_width = box_x / 2; 1218a96d7823Smrg int left_width = box_x - right_width - 1; 1219a96d7823Smrg 1220a96d7823Smrg for (row = 0; row < height; row++) 1221a96d7823Smrg { 1222a96d7823Smrg int sum = 0; 1223a96d7823Smrg int left_size = 0, right_size = 0; 1224a96d7823Smrg 1225a96d7823Smrg srcptr = char_grayscale + (width + 1) * row; 1226a96d7823Smrg dstptr = char_grayscale + (width + 1) * height; /* scratch */ 1227a96d7823Smrg 1228a96d7823Smrg /* We've computed the shape of our full box filter. Now 1229a96d7823Smrg compute the right-hand part of the moving sum */ 1230a96d7823Smrg for (right_size = 0; right_size < right_width; right_size++) 1231a96d7823Smrg sum += srcptr[right_size]; 1232a96d7823Smrg 1233a96d7823Smrg /* Now start moving the sum, growing the box filter, and 1234a96d7823Smrg dropping averages into our scratch buffer */ 1235a96d7823Smrg for (left_size = 0; left_size < left_width; left_size++) 1236a96d7823Smrg { 1237a96d7823Smrg sum += srcptr[right_width]; 1238a96d7823Smrg *dstptr++ = sum / (left_size + right_width + 1); 1239a96d7823Smrg srcptr++; 1240a96d7823Smrg } 1241a96d7823Smrg 1242a96d7823Smrg /* The box filter has reached full width... continue 1243a96d7823Smrg computation of moving average until the right side 1244a96d7823Smrg hits the wall. */ 1245a96d7823Smrg for (col = left_size; col + right_size < width; col++) 1246a96d7823Smrg { 1247a96d7823Smrg sum += srcptr[right_width]; 1248a96d7823Smrg *dstptr++ = sum / box_x; 1249a96d7823Smrg sum -= srcptr[-left_width]; 1250a96d7823Smrg srcptr++; 1251a96d7823Smrg } 1252a96d7823Smrg 1253a96d7823Smrg /* Collapse the right side of the box filter */ 1254a96d7823Smrg for (; right_size > 0; right_size--) 1255a96d7823Smrg { 1256a96d7823Smrg *dstptr++ = sum / (left_width + right_size); 1257a96d7823Smrg sum -= srcptr[-left_width]; 1258a96d7823Smrg srcptr++; 1259a96d7823Smrg } 1260a96d7823Smrg 1261a96d7823Smrg /* Done with the row... copy dest back over source */ 1262a96d7823Smrg memmove(char_grayscale + (width + 1) * row, 1263a96d7823Smrg char_grayscale + (width + 1) * height, 1264a96d7823Smrg width); 1265a96d7823Smrg } 1266a96d7823Smrg } 1267a96d7823Smrg if (box_y > 1) 1268a96d7823Smrg { 1269a96d7823Smrg /* Our box filter has a height > 1... let's filter the columns */ 1270a96d7823Smrg 1271a96d7823Smrg int bottom_height = box_y / 2; 1272a96d7823Smrg int top_height = box_y - bottom_height - 1; 1273a96d7823Smrg 1274a96d7823Smrg for (col = 0; col < width; col++) 1275a96d7823Smrg { 1276a96d7823Smrg int sum = 0; 1277a96d7823Smrg int top_size = 0, bottom_size = 0; 1278a96d7823Smrg 1279a96d7823Smrg srcptr = char_grayscale + col; 1280a96d7823Smrg dstptr = char_grayscale + width; /* scratch */ 1281a96d7823Smrg 1282a96d7823Smrg /* We've computed the shape of our full box filter. Now 1283a96d7823Smrg compute the bottom part of the moving sum */ 1284a96d7823Smrg for (bottom_size = 0; 1285a96d7823Smrg bottom_size < bottom_height; 1286a96d7823Smrg bottom_size++) 1287a96d7823Smrg sum += srcptr[bottom_size * (width + 1)]; 1288a96d7823Smrg 1289a96d7823Smrg /* Now start moving the sum, growing the box filter, and 1290a96d7823Smrg dropping averages into our scratch buffer */ 1291a96d7823Smrg for (top_size = 0; top_size < top_height; top_size++) 1292a96d7823Smrg { 1293a96d7823Smrg sum += srcptr[bottom_height * (width + 1)]; 1294a96d7823Smrg *dstptr = sum / (top_size + bottom_height + 1); 1295a96d7823Smrg dstptr += width + 1; 1296a96d7823Smrg srcptr += width + 1; 1297a96d7823Smrg } 1298a96d7823Smrg 1299a96d7823Smrg /* The box filter has reached full height... continue 1300a96d7823Smrg computation of moving average until the bottom 1301a96d7823Smrg hits the wall. */ 1302a96d7823Smrg for (row = top_size; row + bottom_size < height; row++) 1303a96d7823Smrg { 1304a96d7823Smrg sum += srcptr[bottom_height * (width + 1)]; 1305a96d7823Smrg *dstptr = sum / box_y; 1306a96d7823Smrg dstptr += width + 1; 1307a96d7823Smrg sum -= srcptr[-top_height * (width + 1)]; 1308a96d7823Smrg srcptr += width + 1; 1309a96d7823Smrg } 1310a96d7823Smrg 1311a96d7823Smrg /* Collapse the bottom of the box filter */ 1312a96d7823Smrg for (; bottom_size > 0; bottom_size--) 1313a96d7823Smrg { 1314a96d7823Smrg *dstptr = sum / (top_height + bottom_size); 1315a96d7823Smrg dstptr += width + 1; 1316a96d7823Smrg sum -= srcptr[-top_height * (width + 1)]; 1317a96d7823Smrg srcptr += width + 1; 1318a96d7823Smrg } 1319a96d7823Smrg 1320a96d7823Smrg /* Done with the column... copy dest back over source */ 1321a96d7823Smrg 1322a96d7823Smrg dstptr = char_grayscale + col; 1323a96d7823Smrg srcptr = char_grayscale + width; /* scratch */ 1324a96d7823Smrg for (row = 0; row < height; row++) 1325a96d7823Smrg { 1326a96d7823Smrg *dstptr = *srcptr; 1327a96d7823Smrg dstptr += width + 1; 1328a96d7823Smrg srcptr += width + 1; 1329a96d7823Smrg } 1330a96d7823Smrg } 1331a96d7823Smrg } 1332a96d7823Smrg 1333a96d7823Smrg /* Increase the grayvalue to increase ink a bit */ 1334a96d7823Smrg srcptr = char_grayscale; 1335a96d7823Smrg for (row = 0; row < height; row++) 1336a96d7823Smrg { 1337a96d7823Smrg for (col = 0; col < width; col++) 1338a96d7823Smrg { 1339a96d7823Smrg register int pixvalue = (int)*srcptr * pixmult / 256; 1340a96d7823Smrg if (pixvalue > 255) pixvalue = 255; 1341a96d7823Smrg *srcptr = pixvalue; 1342a96d7823Smrg srcptr++; 1343a96d7823Smrg } 1344a96d7823Smrg srcptr++; 1345a96d7823Smrg } 1346a96d7823Smrg } 1347a96d7823Smrg 1348a96d7823Smrg /* Compute the increment values for the resampling loop */ 1349a96d7823Smrg TRANSFORM_POINT(inv_xform, 1, 0, point); 1350a96d7823Smrg deltaX = (INT32)(point[0] * 65536.0); 1351a96d7823Smrg deltaY = (INT32)(-point[1] * 65536.0); 1352a96d7823Smrg 1353a96d7823Smrg /* Resampling loop: resamples original glyph for generation of new 1354a96d7823Smrg glyph in transformed coordinate system. */ 1355a96d7823Smrg 1356a96d7823Smrg for (row = 0; row < newHeight; row++) 1357a96d7823Smrg { 1358a96d7823Smrg /* Compute inverse transformation for start of this row */ 1359a96d7823Smrg TRANSFORM_POINT(inv_xform, 1360a96d7823Smrg (double)(pci->metrics.leftSideBearing) + .5, 1361a96d7823Smrg (double)(pci->metrics.ascent - row) - .5, 1362a96d7823Smrg point); 1363a96d7823Smrg 1364a96d7823Smrg /* Adjust for coordinate system to get resampling point */ 1365a96d7823Smrg point[0] -= opci->metrics.leftSideBearing; 1366a96d7823Smrg point[1] = opci->metrics.ascent - point[1]; 1367a96d7823Smrg 1368a96d7823Smrg /* Convert to integer coordinates */ 1369a96d7823Smrg xValue = (INT32)(point[0] * 65536.0); 1370a96d7823Smrg yValue = (INT32)(point[1] * 65536.0); 1371a96d7823Smrg 1372a96d7823Smrg if (char_grayscale) 1373a96d7823Smrg { 1374a96d7823Smrg INT32 *temp; 1375a96d7823Smrg for (col = 0; col < newWidth; col++) 1376a96d7823Smrg { 1377a96d7823Smrg register int x = xValue >> 16, y = yValue >> 16; 1378a96d7823Smrg int pixvalue, error; 1379a96d7823Smrg 1380a96d7823Smrg pixvalue = ((x >= 0 && x < width && y >= 0 && y < height) ? 1381a96d7823Smrg char_grayscale[x + y * (width + 1)] : 0) + 1382a96d7823Smrg thisrow[col] / 16; 1383a96d7823Smrg if (pixvalue > 255) pixvalue = 255; 1384a96d7823Smrg else if (pixvalue < 0) pixvalue = 0; 1385a96d7823Smrg 1386a96d7823Smrg /* Choose the bit value and set resulting error value */ 1387a96d7823Smrg if (pixvalue >= 128) 1388a96d7823Smrg { 1389a96d7823Smrg newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7]; 1390a96d7823Smrg error = pixvalue - 255; 1391a96d7823Smrg } 1392a96d7823Smrg else 1393a96d7823Smrg error = -pixvalue; 1394a96d7823Smrg 1395a96d7823Smrg /* Diffuse the error */ 1396a96d7823Smrg thisrow[col + 1] += error * 7; 1397a96d7823Smrg nextrow[col - 1] += error * 3; 1398a96d7823Smrg nextrow[col] += error * 5; 1399a96d7823Smrg nextrow[col + 1] = error; 1400a96d7823Smrg 1401a96d7823Smrg xValue += deltaX; 1402a96d7823Smrg yValue += deltaY; 1403a96d7823Smrg } 1404a96d7823Smrg 1405a96d7823Smrg /* Add in error values that fell off either end */ 1406a96d7823Smrg nextrow[0] += nextrow[-1]; 1407a96d7823Smrg nextrow[newWidth - 2] += thisrow[newWidth]; 1408a96d7823Smrg nextrow[newWidth - 1] += nextrow[newWidth]; 1409a96d7823Smrg nextrow[newWidth] = 0; 1410a96d7823Smrg 1411a96d7823Smrg temp = nextrow; 1412a96d7823Smrg nextrow = thisrow; 1413a96d7823Smrg thisrow = temp; 1414a96d7823Smrg nextrow[-1] = nextrow[0] = 0; 1415a96d7823Smrg } 1416a96d7823Smrg else 1417a96d7823Smrg { 1418a96d7823Smrg for (col = 0; col < newWidth; col++) 1419a96d7823Smrg { 1420a96d7823Smrg register int x = xValue >> 16, y = yValue >> 16; 1421a96d7823Smrg 1422a96d7823Smrg if (x >= 0 && x < width && y >= 0 && y < height) 1423a96d7823Smrg { 1424a96d7823Smrg /* Use point-sampling for rescaling. */ 1425a96d7823Smrg 1426a96d7823Smrg if (bitmap[(x >> 3) + y * bpr] & mask[x & 0x7]) 1427a96d7823Smrg newBitmap[(col >> 3) + row * newBpr] |= mask[col & 0x7]; 1428a96d7823Smrg } 1429a96d7823Smrg 1430a96d7823Smrg xValue += deltaX; 1431a96d7823Smrg yValue += deltaY; 1432a96d7823Smrg } 1433a96d7823Smrg } 1434a96d7823Smrg } 1435a96d7823Smrg 1436a96d7823Smrg 1437a96d7823Smrg if (char_grayscale) 1438a96d7823Smrg { 1439a96d7823Smrg free(char_grayscale); 1440a96d7823Smrg free(diffusion_workspace); 1441a96d7823Smrg } 1442a96d7823Smrg} 1443a96d7823Smrg 1444a96d7823Smrgstatic FontPtr 1445a96d7823SmrgBitmapScaleBitmaps(FontPtr pf, /* scaled font */ 1446a96d7823Smrg FontPtr opf, /* originating font */ 1447a96d7823Smrg double widthMult, /* glyphs width scale factor */ 1448a96d7823Smrg double heightMult, /* glyphs height scale factor */ 1449a96d7823Smrg FontScalablePtr vals) 1450a96d7823Smrg{ 1451a96d7823Smrg register int i; 1452a96d7823Smrg int nchars = 0; 1453a96d7823Smrg char *glyphBytes; 1454a96d7823Smrg BitmapFontPtr bitmapFont, 1455a96d7823Smrg obitmapFont; 1456a96d7823Smrg CharInfoPtr pci, 1457a96d7823Smrg opci; 1458a96d7823Smrg FontInfoPtr pfi; 1459a96d7823Smrg int glyph; 1460a96d7823Smrg unsigned bytestoalloc = 0; 1461a96d7823Smrg int firstCol, lastCol, firstRow, lastRow; 1462a96d7823Smrg 1463a96d7823Smrg double xform[4], inv_xform[4]; 1464a96d7823Smrg double xmult, ymult; 1465a96d7823Smrg 1466a96d7823Smrg bitmapFont = (BitmapFontPtr) pf->fontPrivate; 1467a96d7823Smrg obitmapFont = (BitmapFontPtr) opf->fontPrivate; 1468a96d7823Smrg 1469a96d7823Smrg if (!compute_xform_matrix(vals, widthMult, heightMult, xform, 1470a96d7823Smrg inv_xform, &xmult, &ymult)) 1471a96d7823Smrg goto bail; 1472a96d7823Smrg 1473a96d7823Smrg pfi = &pf->info; 1474a96d7823Smrg firstCol = pfi->firstCol; 1475a96d7823Smrg lastCol = pfi->lastCol; 1476a96d7823Smrg firstRow = pfi->firstRow; 1477a96d7823Smrg lastRow = pfi->lastRow; 1478a96d7823Smrg 1479a96d7823Smrg nchars = (lastRow - firstRow + 1) * (lastCol - firstCol + 1); 1480a96d7823Smrg glyph = pf->glyph; 1481a96d7823Smrg for (i = 0; i < nchars; i++) 1482a96d7823Smrg { 1483a96d7823Smrg if ((pci = ACCESSENCODING(bitmapFont->encoding, i))) 1484a96d7823Smrg bytestoalloc += BYTES_FOR_GLYPH(pci, glyph); 1485a96d7823Smrg } 1486a96d7823Smrg 1487a96d7823Smrg /* Do we add the font malloc stuff for VALUE ADDED ? */ 1488a96d7823Smrg /* Will need to remember to free in the Unload routine */ 1489a96d7823Smrg 1490a96d7823Smrg 1491a96d7823Smrg bitmapFont->bitmaps = calloc(1, bytestoalloc); 1492a96d7823Smrg if (!bitmapFont->bitmaps) { 1493a96d7823Smrg fprintf(stderr, "Error: Couldn't allocate bitmaps (%d)\n", bytestoalloc); 1494a96d7823Smrg goto bail; 1495a96d7823Smrg } 1496a96d7823Smrg 1497a96d7823Smrg glyphBytes = bitmapFont->bitmaps; 1498a96d7823Smrg for (i = 0; i < nchars; i++) 1499a96d7823Smrg { 1500a96d7823Smrg if ((pci = ACCESSENCODING(bitmapFont->encoding, i)) && 1501a96d7823Smrg (opci = ACCESSENCODING(obitmapFont->encoding, OLDINDEX(i)))) 1502a96d7823Smrg { 1503a96d7823Smrg pci->bits = glyphBytes; 1504a96d7823Smrg ScaleBitmap (pf, opci, pci, inv_xform, 1505a96d7823Smrg widthMult, heightMult); 1506a96d7823Smrg glyphBytes += BYTES_FOR_GLYPH(pci, glyph); 1507a96d7823Smrg } 1508a96d7823Smrg } 1509a96d7823Smrg return pf; 1510a96d7823Smrg 1511a96d7823Smrgbail: 1512a96d7823Smrg if (pf) 1513a96d7823Smrg free(pf); 1514a96d7823Smrg if (bitmapFont) { 1515a96d7823Smrg free(bitmapFont->metrics); 1516a96d7823Smrg free(bitmapFont->ink_metrics); 1517a96d7823Smrg free(bitmapFont->bitmaps); 1518a96d7823Smrg if(bitmapFont->encoding) 1519a96d7823Smrg for(i=0; i<NUM_SEGMENTS(nchars); i++) 1520a96d7823Smrg free(bitmapFont->encoding[i]); 1521a96d7823Smrg free(bitmapFont->encoding); 1522a96d7823Smrg } 1523a96d7823Smrg return NULL; 1524a96d7823Smrg} 1525a96d7823Smrg 1526a96d7823Smrg/* ARGSUSED */ 1527a96d7823Smrgint 1528a96d7823SmrgBitmapOpenScalable (FontPathElementPtr fpe, 1529a96d7823Smrg FontPtr *pFont, 1530a96d7823Smrg int flags, 1531a96d7823Smrg FontEntryPtr entry, 1532a96d7823Smrg char *fileName, /* unused */ 1533a96d7823Smrg FontScalablePtr vals, 1534a96d7823Smrg fsBitmapFormat format, 1535a96d7823Smrg fsBitmapFormatMask fmask, 1536a96d7823Smrg FontPtr non_cachable_font) /* We don't do licensing */ 1537a96d7823Smrg{ 1538a96d7823Smrg FontScalableRec best; 1539a96d7823Smrg FontPtr font = NullFont; 1540a96d7823Smrg double dx, sdx, 1541a96d7823Smrg dy, sdy, 1542a96d7823Smrg savedX, savedY; 1543a96d7823Smrg FontPropPtr props; 1544a96d7823Smrg char *isStringProp = NULL; 1545a96d7823Smrg int propCount; 1546a96d7823Smrg int status; 1547a96d7823Smrg long sWidth; 1548a96d7823Smrg 1549a96d7823Smrg FontEntryPtr scaleFrom; 1550a96d7823Smrg FontPathElementPtr scaleFPE = NULL; 1551a96d7823Smrg FontPtr sourceFont; 1552a96d7823Smrg char fontName[MAXFONTNAMELEN]; 1553a96d7823Smrg 1554a96d7823Smrg /* Can't deal with mix-endian fonts yet */ 1555a96d7823Smrg 1556a96d7823Smrg 1557a96d7823Smrg /* Reject outrageously small font sizes to keep the math from 1558a96d7823Smrg blowing up. */ 1559a96d7823Smrg if (get_matrix_vertical_component(vals->pixel_matrix) < 1.0 || 1560a96d7823Smrg get_matrix_horizontal_component(vals->pixel_matrix) < 1.0) 1561a96d7823Smrg return BadFontName; 1562a96d7823Smrg 1563a96d7823Smrg scaleFrom = FindBestToScale(fpe, entry, vals, &best, &dx, &dy, &sdx, &sdy, 1564a96d7823Smrg &scaleFPE); 1565a96d7823Smrg 1566a96d7823Smrg if (!scaleFrom) 1567a96d7823Smrg return BadFontName; 1568a96d7823Smrg 1569a96d7823Smrg status = FontFileOpenBitmap(scaleFPE, &sourceFont, LoadAll, scaleFrom, 1570a96d7823Smrg format, fmask); 1571a96d7823Smrg 1572a96d7823Smrg if (status != Successful) 1573a96d7823Smrg return BadFontName; 1574a96d7823Smrg 1575a96d7823Smrg if (!vals->width) 1576a96d7823Smrg vals->width = best.width * dx; 1577a96d7823Smrg 1578a96d7823Smrg /* Compute the scaled font */ 1579a96d7823Smrg 1580a96d7823Smrg savedX = dx; 1581a96d7823Smrg savedY = dy; 1582a96d7823Smrg font = ScaleFont(sourceFont, dx, dy, sdx, sdy, vals, &dx, &dy, &sWidth); 1583a96d7823Smrg if (font) 1584a96d7823Smrg font = BitmapScaleBitmaps(font, sourceFont, savedX, savedY, vals); 1585a96d7823Smrg 1586a96d7823Smrg if (!font) 1587a96d7823Smrg { 1588a96d7823Smrg if (!sourceFont->refcnt) 1589a96d7823Smrg FontFileCloseFont((FontPathElementPtr) 0, sourceFont); 1590a96d7823Smrg return AllocError; 1591a96d7823Smrg } 1592a96d7823Smrg 1593a96d7823Smrg /* Prepare font properties for the new font */ 1594a96d7823Smrg 1595a96d7823Smrg strcpy (fontName, scaleFrom->name.name); 1596a96d7823Smrg FontParseXLFDName (fontName, vals, FONT_XLFD_REPLACE_VALUE); 1597a96d7823Smrg 1598a96d7823Smrg propCount = ComputeScaledProperties(&sourceFont->info, fontName, vals, 1599a96d7823Smrg dx, dy, sdx, sdy, sWidth, &props, 1600a96d7823Smrg &isStringProp); 1601a96d7823Smrg 1602a96d7823Smrg if (!sourceFont->refcnt) 1603a96d7823Smrg FontFileCloseFont((FontPathElementPtr) 0, sourceFont); 1604a96d7823Smrg 1605a96d7823Smrg font->info.props = props; 1606a96d7823Smrg font->info.nprops = propCount; 1607a96d7823Smrg font->info.isStringProp = isStringProp; 1608a96d7823Smrg 1609a96d7823Smrg if (propCount && (!props || !isStringProp)) 1610a96d7823Smrg { 1611a96d7823Smrg bitmapUnloadScalable(font); 1612a96d7823Smrg return AllocError; 1613a96d7823Smrg } 1614a96d7823Smrg 1615a96d7823Smrg *pFont = font; 1616a96d7823Smrg return Successful; 1617a96d7823Smrg} 1618a96d7823Smrg 1619a96d7823Smrgint 1620a96d7823SmrgBitmapGetInfoScalable (FontPathElementPtr fpe, 1621a96d7823Smrg FontInfoPtr pFontInfo, 1622a96d7823Smrg FontEntryPtr entry, 1623a96d7823Smrg FontNamePtr fontName, 1624a96d7823Smrg char *fileName, 1625a96d7823Smrg FontScalablePtr vals) 1626a96d7823Smrg{ 1627a96d7823Smrg FontPtr pfont; 1628a96d7823Smrg int flags = 0; 1629a96d7823Smrg long format = 0; /* It doesn't matter what format for just info */ 1630a96d7823Smrg long fmask = 0; 1631a96d7823Smrg int ret; 1632a96d7823Smrg 1633a96d7823Smrg ret = BitmapOpenScalable(fpe, &pfont, flags, entry, fileName, vals, 1634a96d7823Smrg format, fmask, NULL); 1635a96d7823Smrg if (ret != Successful) 1636a96d7823Smrg return ret; 1637a96d7823Smrg *pFontInfo = pfont->info; 1638a96d7823Smrg 1639a96d7823Smrg pfont->info.nprops = 0; 1640a96d7823Smrg pfont->info.props = NULL; 1641a96d7823Smrg pfont->info.isStringProp = NULL; 1642a96d7823Smrg 1643a96d7823Smrg (*pfont->unload_font)(pfont); 1644a96d7823Smrg return Successful; 1645a96d7823Smrg} 1646a96d7823Smrg 1647a96d7823Smrgstatic void 1648a96d7823SmrgbitmapUnloadScalable (FontPtr pFont) 1649a96d7823Smrg{ 1650a96d7823Smrg BitmapFontPtr bitmapFont; 1651a96d7823Smrg FontInfoPtr pfi; 1652a96d7823Smrg int i, nencoding; 1653a96d7823Smrg 1654a96d7823Smrg bitmapFont = (BitmapFontPtr) pFont->fontPrivate; 1655a96d7823Smrg pfi = &pFont->info; 1656a96d7823Smrg free (pfi->props); 1657a96d7823Smrg free (pfi->isStringProp); 1658a96d7823Smrg if(bitmapFont->encoding) { 1659a96d7823Smrg nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) * 1660a96d7823Smrg (pFont->info.lastRow - pFont->info.firstRow + 1); 1661a96d7823Smrg for(i=0; i<NUM_SEGMENTS(nencoding); i++) 1662a96d7823Smrg free(bitmapFont->encoding[i]); 1663a96d7823Smrg } 1664a96d7823Smrg free (bitmapFont->encoding); 1665a96d7823Smrg free (bitmapFont->bitmaps); 1666a96d7823Smrg free (bitmapFont->ink_metrics); 1667a96d7823Smrg free (bitmapFont->metrics); 1668a96d7823Smrg free (pFont->fontPrivate); 1669a96d7823Smrg DestroyFontRec (pFont); 1670a96d7823Smrg} 1671