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