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