fontscale.c revision 7f7f5e4e
1/* $Xorg: fontscale.c,v 1.5 2001/02/09 02:04:03 xorgcvs Exp $ */ 2 3/* 4 5Copyright 1991, 1998 The Open Group 6 7Permission to use, copy, modify, distribute, and sell this software and its 8documentation for any purpose is hereby granted without fee, provided that 9the above copyright notice appear in all copies and that both that 10copyright notice and this permission notice appear in supporting 11documentation. 12 13The above copyright notice and this permission notice shall be included in 14all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 23Except as contained in this notice, the name of The Open Group shall not be 24used in advertising or otherwise to promote the sale, use or other dealings 25in this Software without prior written authorization from The Open Group. 26 27*/ 28/* $XFree86: xc/lib/font/fontfile/fontscale.c,v 3.9 2001/08/27 19:49:54 dawes Exp $ */ 29 30/* 31 * Author: Keith Packard, MIT X Consortium 32 */ 33 34#ifdef HAVE_CONFIG_H 35#include <config.h> 36#endif 37#include <X11/fonts/fntfilst.h> 38#include <math.h> 39 40Bool 41FontFileAddScaledInstance (FontEntryPtr entry, FontScalablePtr vals, 42 FontPtr pFont, char *bitmapName) 43{ 44 FontScalableEntryPtr scalable; 45 FontScalableExtraPtr extra; 46 FontScaledPtr new; 47 int newsize; 48 49 scalable = &entry->u.scalable; 50 extra = scalable->extra; 51 if (extra->numScaled == extra->sizeScaled) 52 { 53 newsize = extra->sizeScaled + 4; 54 new = realloc (extra->scaled, newsize * sizeof (FontScaledRec)); 55 if (!new) 56 return FALSE; 57 extra->sizeScaled = newsize; 58 extra->scaled = new; 59 } 60 new = &extra->scaled[extra->numScaled++]; 61 new->vals = *vals; 62 new->pFont = pFont; 63 new->bitmap = (FontEntryPtr) bitmapName; 64 if (pFont) 65 pFont->fpePrivate = (pointer) entry; 66 return TRUE; 67} 68 69/* Must call this after the directory is sorted */ 70 71void 72FontFileSwitchStringsToBitmapPointers (FontDirectoryPtr dir) 73{ 74 int s; 75 int b; 76 int i; 77 FontEntryPtr scalable; 78 FontEntryPtr nonScalable; 79 FontScaledPtr scaled; 80 FontScalableExtraPtr extra; 81 82 scalable = dir->scalable.entries; 83 nonScalable = dir->nonScalable.entries; 84 for (s = 0; s < dir->scalable.used; s++) 85 { 86 extra = scalable[s].u.scalable.extra; 87 scaled = extra->scaled; 88 for (i = 0; i < extra->numScaled; i++) 89 for (b = 0; b < dir->nonScalable.used; b++) 90 if (nonScalable[b].name.name == (char *) scaled[i].bitmap) 91 scaled[i].bitmap = &nonScalable[b]; 92 } 93} 94 95void 96FontFileRemoveScaledInstance (FontEntryPtr entry, FontPtr pFont) 97{ 98 FontScalableEntryPtr scalable; 99 FontScalableExtraPtr extra; 100 int i; 101 102 scalable = &entry->u.scalable; 103 extra = scalable->extra; 104 for (i = 0; i < extra->numScaled; i++) 105 { 106 if (extra->scaled[i].pFont == pFont) 107 { 108 if (extra->scaled[i].vals.ranges) 109 free (extra->scaled[i].vals.ranges); 110 extra->numScaled--; 111 for (; i < extra->numScaled; i++) 112 extra->scaled[i] = extra->scaled[i+1]; 113 } 114 } 115} 116 117Bool 118FontFileCompleteXLFD (FontScalablePtr vals, FontScalablePtr def) 119{ 120 FontResolutionPtr res; 121 int num_res; 122 double sx, sy, temp_matrix[4]; 123 double pixel_setsize_adjustment = 1.0; 124 /* 125 * If two of the three vertical scale values are specified, compute the 126 * third. If all three are specified, make sure they are consistent 127 * (within a pixel) 128 * 129 * One purpose of this procedure is to complete XLFD names in a 130 * repeatable manner. That is, if the user partially specifies 131 * a name (say, pixelsize but not pointsize), the results generated 132 * here result in a fully specified name that will result in the 133 * same font. 134 */ 135 136 res = GetClientResolutions(&num_res); 137 138 if (!(vals->values_supplied & PIXELSIZE_MASK) || 139 !(vals->values_supplied & POINTSIZE_MASK)) 140 { 141 /* If resolution(s) unspecified and cannot be computed from 142 pixelsize and pointsize, get appropriate defaults. */ 143 144 if (num_res) 145 { 146 if (vals->x <= 0) 147 vals->x = res->x_resolution; 148 if (vals->y <= 0) 149 vals->y = res->y_resolution; 150 } 151 152 if (vals->x <= 0) 153 vals->x = def->x; 154 if (vals->y <= 0) 155 vals->y = def->y; 156 } 157 else 158 { 159 /* If needed, compute resolution values from the pixel and 160 pointsize information we were given. This problem is 161 overdetermined (four equations, two unknowns), but we don't 162 check for inconsistencies here. If they exist, they will 163 show up in later tests for the point and pixel sizes. */ 164 165 if (vals->y <= 0) 166 { 167 double x = hypot(vals->pixel_matrix[1], vals->pixel_matrix[3]); 168 double y = hypot(vals->point_matrix[1], vals->point_matrix[3]); 169 if (y < EPS) return FALSE; 170 vals->y = (int)(x * 72.27 / y + .5); 171 } 172 if (vals->x <= 0) 173 { 174 /* If the pixelsize was given as an array, or as a scalar that 175 has been normalized for the pixel shape, we have enough 176 information to compute a separate horizontal resolution */ 177 178 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY || 179 (vals->values_supplied & PIXELSIZE_MASK) == 180 PIXELSIZE_SCALAR_NORMALIZED) 181 { 182 double x = hypot(vals->pixel_matrix[0], vals->pixel_matrix[2]); 183 double y = hypot(vals->point_matrix[0], vals->point_matrix[2]); 184 if (y < EPS) return FALSE; 185 vals->x = (int)(x * 72.27 / y + .5); 186 } 187 else 188 { 189 /* Not enough information in the pixelsize array. Just 190 assume the pixels are square. */ 191 vals->x = vals->y; 192 } 193 } 194 } 195 196 if (vals->x <= 0 || vals->y <= 0) return FALSE; 197 198 /* If neither pixelsize nor pointsize is defined, take the pointsize 199 from the defaults structure we've been passed. */ 200 if (!(vals->values_supplied & PIXELSIZE_MASK) && 201 !(vals->values_supplied & POINTSIZE_MASK)) 202 { 203 if (num_res) 204 { 205 vals->point_matrix[0] = 206 vals->point_matrix[3] = (double)res->point_size / 10.0; 207 vals->point_matrix[1] = 208 vals->point_matrix[2] = 0; 209 vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) | 210 POINTSIZE_SCALAR; 211 } 212 else if (def->values_supplied & POINTSIZE_MASK) 213 { 214 vals->point_matrix[0] = def->point_matrix[0]; 215 vals->point_matrix[1] = def->point_matrix[1]; 216 vals->point_matrix[2] = def->point_matrix[2]; 217 vals->point_matrix[3] = def->point_matrix[3]; 218 vals->values_supplied = (vals->values_supplied & ~POINTSIZE_MASK) | 219 (def->values_supplied & POINTSIZE_MASK); 220 } 221 else return FALSE; 222 } 223 224 /* At this point, at least two of the three vertical scale values 225 should be specified. Our job now is to compute the missing ones 226 and check for agreement between overspecified values */ 227 228 /* If pixelsize was specified by a scalar, we need to fix the matrix 229 now that we know the resolutions. */ 230 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_SCALAR) 231 { 232 /* pixel_setsize_adjustment used below to modify permissible 233 error in pixel/pointsize matching, since multiplying a 234 number rounded to integer changes the amount of the error 235 caused by the rounding */ 236 237 pixel_setsize_adjustment = (double)vals->x / (double)vals->y; 238 vals->pixel_matrix[0] *= pixel_setsize_adjustment; 239 vals->values_supplied = (vals->values_supplied & ~PIXELSIZE_MASK) | 240 PIXELSIZE_SCALAR_NORMALIZED; 241 } 242 243 sx = (double)vals->x / 72.27; 244 sy = (double)vals->y / 72.27; 245 246 /* If a pointsize was specified, make sure pixelsize is consistent 247 to within 1 pixel, then replace pixelsize with a consistent 248 floating-point value. */ 249 250 if (vals->values_supplied & POINTSIZE_MASK) 251 { 252 recompute_pixelsize: ; 253 temp_matrix[0] = vals->point_matrix[0] * sx; 254 temp_matrix[1] = vals->point_matrix[1] * sy; 255 temp_matrix[2] = vals->point_matrix[2] * sx; 256 temp_matrix[3] = vals->point_matrix[3] * sy; 257 if (vals->values_supplied & PIXELSIZE_MASK) 258 { 259 if (fabs(vals->pixel_matrix[0] - temp_matrix[0]) > 260 pixel_setsize_adjustment || 261 fabs(vals->pixel_matrix[1] - temp_matrix[1]) > 1 || 262 fabs(vals->pixel_matrix[2] - temp_matrix[2]) > 1 || 263 fabs(vals->pixel_matrix[3] - temp_matrix[3]) > 1) 264 return FALSE; 265 } 266 if ((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY && 267 (vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR) 268 { 269 /* In the special case that pixelsize came as an array and 270 pointsize as a scalar, recompute the pointsize matrix 271 from the pixelsize matrix. */ 272 goto recompute_pointsize; 273 } 274 275 /* Refresh pixel matrix with precise values computed from 276 pointsize and resolution. */ 277 vals->pixel_matrix[0] = temp_matrix[0]; 278 vals->pixel_matrix[1] = temp_matrix[1]; 279 vals->pixel_matrix[2] = temp_matrix[2]; 280 vals->pixel_matrix[3] = temp_matrix[3]; 281 282 /* Set values_supplied for pixel to match that for point */ 283 vals->values_supplied = 284 (vals->values_supplied & ~PIXELSIZE_MASK) | 285 (((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_ARRAY) ? 286 PIXELSIZE_ARRAY : PIXELSIZE_SCALAR_NORMALIZED); 287 } 288 else 289 { 290 /* Pointsize unspecified... compute from pixel size and 291 resolutions */ 292 recompute_pointsize: ; 293 if (fabs(sx) < EPS || fabs(sy) < EPS) return FALSE; 294 vals->point_matrix[0] = vals->pixel_matrix[0] / sx; 295 vals->point_matrix[1] = vals->pixel_matrix[1] / sy; 296 vals->point_matrix[2] = vals->pixel_matrix[2] / sx; 297 vals->point_matrix[3] = vals->pixel_matrix[3] / sy; 298 299 /* Set values_supplied for pixel to match that for point */ 300 vals->values_supplied = 301 (vals->values_supplied & ~POINTSIZE_MASK) | 302 (((vals->values_supplied & PIXELSIZE_MASK) == PIXELSIZE_ARRAY) ? 303 POINTSIZE_ARRAY : POINTSIZE_SCALAR); 304 305 /* If we computed scalar pointsize from scalar pixelsize, round 306 pointsize to decipoints and recompute pixelsize so we end up 307 with a repeatable name */ 308 if ((vals->values_supplied & POINTSIZE_MASK) == POINTSIZE_SCALAR) 309 { 310 /* Off-diagonal elements should be zero since no matrix was 311 specified. */ 312 vals->point_matrix[0] = 313 (double)(int)(vals->point_matrix[0] * 10.0 + .5) / 10.0; 314 vals->point_matrix[3] = 315 (double)(int)(vals->point_matrix[3] * 10.0 + .5) / 10.0; 316 goto recompute_pixelsize; 317 } 318 } 319 320 /* We've succeeded. Round everything to a few decimal places 321 for repeatability. */ 322 323 vals->pixel_matrix[0] = xlfd_round_double(vals->pixel_matrix[0]); 324 vals->pixel_matrix[1] = xlfd_round_double(vals->pixel_matrix[1]); 325 vals->pixel_matrix[2] = xlfd_round_double(vals->pixel_matrix[2]); 326 vals->pixel_matrix[3] = xlfd_round_double(vals->pixel_matrix[3]); 327 vals->point_matrix[0] = xlfd_round_double(vals->point_matrix[0]); 328 vals->point_matrix[1] = xlfd_round_double(vals->point_matrix[1]); 329 vals->point_matrix[2] = xlfd_round_double(vals->point_matrix[2]); 330 vals->point_matrix[3] = xlfd_round_double(vals->point_matrix[3]); 331 332 /* Fill in the deprecated fields for the benefit of rasterizers 333 that do not handle the matrices. */ 334 vals->point = vals->point_matrix[3] * 10; 335 vals->pixel = vals->pixel_matrix[3]; 336 337 return TRUE; 338} 339 340static Bool 341MatchScalable (FontScalablePtr a, FontScalablePtr b) 342{ 343 int i; 344 345 /* Some asymmetry here: we assume that the first argument (a) is 346 the table entry and the second (b) the item we're trying to match 347 (the key). We'll consider the fonts matched if the relevant 348 metrics match *and* if a) the table entry doesn't have charset 349 subsetting or b) the table entry has identical charset subsetting 350 to that in the key. We could add logic to check if the table 351 entry has a superset of the charset required by the key, but 352 we'll resist the urge for now. */ 353 354#define EQUAL(a,b) ((a)[0] == (b)[0] && \ 355 (a)[1] == (b)[1] && \ 356 (a)[2] == (b)[2] && \ 357 (a)[3] == (b)[3]) 358 359 if (!(a->x == b->x && 360 a->y == b->y && 361 (a->width == b->width || a->width == 0 || b->width == 0 || b->width == -1) && 362 (!(b->values_supplied & PIXELSIZE_MASK) || 363 ((a->values_supplied & PIXELSIZE_MASK) == 364 (b->values_supplied & PIXELSIZE_MASK) && 365 EQUAL(a->pixel_matrix, b->pixel_matrix))) && 366 (!(b->values_supplied & POINTSIZE_MASK) || 367 ((a->values_supplied & POINTSIZE_MASK) == 368 (b->values_supplied & POINTSIZE_MASK) && 369 EQUAL(a->point_matrix, b->point_matrix))) && 370 (a->nranges == 0 || a->nranges == b->nranges))) 371 return FALSE; 372 373 for (i = 0; i < a->nranges; i++) 374 if (a->ranges[i].min_char_low != b->ranges[i].min_char_low || 375 a->ranges[i].min_char_high != b->ranges[i].min_char_high || 376 a->ranges[i].max_char_low != b->ranges[i].max_char_low || 377 a->ranges[i].max_char_high != b->ranges[i].max_char_high) 378 return FALSE; 379 380 return TRUE; 381} 382 383FontScaledPtr 384FontFileFindScaledInstance (FontEntryPtr entry, FontScalablePtr vals, 385 int noSpecificSize) 386{ 387 FontScalableEntryPtr scalable; 388 FontScalableExtraPtr extra; 389 FontScalablePtr mvals; 390 int dist, i; 391 int mini; 392 double mindist; 393 register double temp, sum=0.0; 394 395#define NORMDIFF(a, b) ( \ 396 temp = (a)[0] - (b)[0], \ 397 sum = temp * temp, \ 398 temp = (a)[1] - (b)[1], \ 399 sum += temp * temp, \ 400 temp = (a)[2] - (b)[2], \ 401 sum += temp * temp, \ 402 temp = (a)[3] - (b)[3], \ 403 sum + temp * temp ) 404 405 scalable = &entry->u.scalable; 406 extra = scalable->extra; 407 if (noSpecificSize && extra->numScaled) 408 { 409 mini = 0; 410 mindist = NORMDIFF(extra->scaled[0].vals.point_matrix, 411 vals->point_matrix); 412 for (i = 1; i < extra->numScaled; i++) 413 { 414 if (extra->scaled[i].pFont && 415 !extra->scaled[i].pFont->info.cachable) continue; 416 mvals = &extra->scaled[i].vals; 417 dist = NORMDIFF(mvals->point_matrix, vals->point_matrix); 418 if (dist < mindist) 419 { 420 mindist = dist; 421 mini = i; 422 } 423 } 424 if (extra->scaled[mini].pFont && 425 !extra->scaled[mini].pFont->info.cachable) return 0; 426 return &extra->scaled[mini]; 427 } 428 else 429 { 430 /* See if we've scaled to this value yet */ 431 for (i = 0; i < extra->numScaled; i++) 432 { 433 if (extra->scaled[i].pFont && 434 !extra->scaled[i].pFont->info.cachable) continue; 435 if (MatchScalable (&extra->scaled[i].vals, vals)) 436 return &extra->scaled[i]; 437 } 438 } 439 return 0; 440} 441