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