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