| File: | xftfreetype.c |
| Location: | line 135, column 27 |
| Description: | Division by zero |
| 1 | /* | |||
| 2 | * Copyright © 2000 Keith Packard | |||
| 3 | * | |||
| 4 | * Permission to use, copy, modify, distribute, and sell this software and its | |||
| 5 | * documentation for any purpose is hereby granted without fee, provided that | |||
| 6 | * the above copyright notice appear in all copies and that both that | |||
| 7 | * copyright notice and this permission notice appear in supporting | |||
| 8 | * documentation, and that the name of Keith Packard not be used in | |||
| 9 | * advertising or publicity pertaining to distribution of the software without | |||
| 10 | * specific, written prior permission. Keith Packard makes no | |||
| 11 | * representations about the suitability of this software for any purpose. It | |||
| 12 | * is provided "as is" without express or implied warranty. | |||
| 13 | * | |||
| 14 | * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |||
| 15 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | |||
| 16 | * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |||
| 17 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | |||
| 18 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | |||
| 19 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | |||
| 20 | * PERFORMANCE OF THIS SOFTWARE. | |||
| 21 | */ | |||
| 22 | ||||
| 23 | #include "xftint.h" | |||
| 24 | ||||
| 25 | _X_HIDDEN__attribute__((visibility("hidden"))) FT_Library _XftFTlibrary; | |||
| 26 | ||||
| 27 | #define FT_Matrix_Equal(a,b)((a)->xx == (b)->xx && (a)->yy == (b)->yy && (a)->xy == (b)->xy && (a)->yx == (b)->yx) ((a)->xx == (b)->xx && \ | |||
| 28 | (a)->yy == (b)->yy && \ | |||
| 29 | (a)->xy == (b)->xy && \ | |||
| 30 | (a)->yx == (b)->yx) | |||
| 31 | /* | |||
| 32 | * List of all open files (each face in a file is managed separately) | |||
| 33 | */ | |||
| 34 | ||||
| 35 | static XftFtFile *_XftFtFiles; | |||
| 36 | static int XftMaxFreeTypeFiles = 5; | |||
| 37 | ||||
| 38 | static XftFtFile * | |||
| 39 | _XftGetFile (const FcChar8 *file, int id) | |||
| 40 | { | |||
| 41 | XftFtFile *f; | |||
| 42 | ||||
| 43 | if (!XftInitFtLibrary ()) | |||
| 44 | return NULL((void*)0); | |||
| 45 | ||||
| 46 | for (f = _XftFtFiles; f; f = f->next) | |||
| 47 | { | |||
| 48 | if (!strcmp (f->file, (char *) file) && f->id == id) | |||
| 49 | { | |||
| 50 | ++f->ref; | |||
| 51 | if (XftDebug () & XFT_DBG_REF16) | |||
| 52 | printf ("FontFile %s/%d matches existing (%d)\n", | |||
| 53 | file, id, f->ref); | |||
| 54 | return f; | |||
| 55 | } | |||
| 56 | } | |||
| 57 | f = malloc (sizeof (XftFtFile) + strlen ((char *) file) + 1); | |||
| 58 | if (!f) | |||
| 59 | return NULL((void*)0); | |||
| 60 | ||||
| 61 | XftMemAlloc (XFT_MEM_FILE2, sizeof (XftFtFile) + strlen ((char *) file) + 1); | |||
| 62 | if (XftDebug () & XFT_DBG_REF16) | |||
| 63 | printf ("FontFile %s/%d matches new\n", | |||
| 64 | file, id); | |||
| 65 | f->next = _XftFtFiles; | |||
| 66 | _XftFtFiles = f; | |||
| 67 | ||||
| 68 | f->ref = 1; | |||
| 69 | ||||
| 70 | f->file = (char *) (f+1); | |||
| 71 | strcpy (f->file, (char *) file)__builtin___strcpy_chk (f->file, (char *) file, __builtin_object_size (f->file, 2 > 1 ? 1 : 0)); | |||
| 72 | f->id = id; | |||
| 73 | ||||
| 74 | f->lock = 0; | |||
| 75 | f->face = NULL((void*)0); | |||
| 76 | f->xsize = 0; | |||
| 77 | f->ysize = 0; | |||
| 78 | f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; | |||
| 79 | return f; | |||
| 80 | } | |||
| 81 | ||||
| 82 | static XftFtFile * | |||
| 83 | _XftGetFaceFile (FT_Face face) | |||
| 84 | { | |||
| 85 | XftFtFile *f; | |||
| 86 | ||||
| 87 | f = malloc (sizeof (XftFtFile)); | |||
| 88 | if (!f) | |||
| 89 | return NULL((void*)0); | |||
| 90 | XftMemAlloc (XFT_MEM_FILE2, sizeof(XftFtFile)); | |||
| 91 | f->next = NULL((void*)0); | |||
| 92 | ||||
| 93 | f->ref = 1; | |||
| 94 | ||||
| 95 | f->file = NULL((void*)0); | |||
| 96 | f->id = 0; | |||
| 97 | f->lock = 0; | |||
| 98 | f->face = face; | |||
| 99 | f->xsize = 0; | |||
| 100 | f->ysize = 0; | |||
| 101 | f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; | |||
| 102 | return f; | |||
| 103 | } | |||
| 104 | ||||
| 105 | static int | |||
| 106 | _XftNumFiles (void) | |||
| 107 | { | |||
| 108 | XftFtFile *f; | |||
| 109 | int count = 0; | |||
| 110 | for (f = _XftFtFiles; f; f = f->next) | |||
| 111 | if (f->face && !f->lock) | |||
| 112 | ++count; | |||
| 113 | return count; | |||
| 114 | } | |||
| 115 | ||||
| 116 | static XftFtFile * | |||
| 117 | _XftNthFile (int n) | |||
| 118 | { | |||
| 119 | XftFtFile *f; | |||
| 120 | int count = 0; | |||
| 121 | for (f = _XftFtFiles; f; f = f->next) | |||
| 122 | if (f->face && !f->lock) | |||
| 123 | if (count++ == n) | |||
| 124 | break; | |||
| 125 | return f; | |||
| 126 | } | |||
| 127 | ||||
| 128 | static void | |||
| 129 | _XftUncacheFiles (void) | |||
| 130 | { | |||
| 131 | int n; | |||
| 132 | XftFtFile *f; | |||
| 133 | while ((n = _XftNumFiles ()) > XftMaxFreeTypeFiles) | |||
| 134 | { | |||
| 135 | f = _XftNthFile (rand () % n); | |||
| ||||
| 136 | if (f) | |||
| 137 | { | |||
| 138 | if (XftDebug() & XFT_DBG_REF16) | |||
| 139 | printf ("Discard file %s/%d from cache\n", | |||
| 140 | f->file, f->id); | |||
| 141 | FT_Done_Face (f->face); | |||
| 142 | f->face = NULL((void*)0); | |||
| 143 | } | |||
| 144 | } | |||
| 145 | } | |||
| 146 | ||||
| 147 | static FT_Face | |||
| 148 | _XftLockFile (XftFtFile *f) | |||
| 149 | { | |||
| 150 | ++f->lock; | |||
| 151 | if (!f->face) | |||
| 152 | { | |||
| 153 | if (XftDebug() & XFT_DBG_REF16) | |||
| 154 | printf ("Loading file %s/%d\n", f->file, f->id); | |||
| 155 | if (FT_New_Face (_XftFTlibrary, f->file, f->id, &f->face)) | |||
| 156 | --f->lock; | |||
| 157 | ||||
| 158 | f->xsize = 0; | |||
| 159 | f->ysize = 0; | |||
| 160 | f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; | |||
| 161 | _XftUncacheFiles (); | |||
| 162 | } | |||
| 163 | return f->face; | |||
| 164 | } | |||
| 165 | ||||
| 166 | static void | |||
| 167 | _XftLockError (const char *reason) | |||
| 168 | { | |||
| 169 | fprintf (stderr__stderrp, "Xft: locking error %s\n", reason); | |||
| 170 | } | |||
| 171 | ||||
| 172 | static void | |||
| 173 | _XftUnlockFile (XftFtFile *f) | |||
| 174 | { | |||
| 175 | if (--f->lock < 0) | |||
| 176 | _XftLockError ("too many file unlocks"); | |||
| 177 | } | |||
| 178 | ||||
| 179 | #define X_SIZE(face,i)((face)->available_sizes[i].x_ppem) ((face)->available_sizes[i].x_ppem) | |||
| 180 | #define Y_SIZE(face,i)((face)->available_sizes[i].y_ppem) ((face)->available_sizes[i].y_ppem) | |||
| 181 | ||||
| 182 | _X_HIDDEN__attribute__((visibility("hidden"))) FcBool | |||
| 183 | _XftSetFace (XftFtFile *f, FT_F26Dot6 xsize, FT_F26Dot6 ysize, FT_Matrix *matrix) | |||
| 184 | { | |||
| 185 | FT_Face face = f->face; | |||
| 186 | ||||
| 187 | if (f->xsize != xsize || f->ysize != ysize) | |||
| 188 | { | |||
| 189 | if (XftDebug() & XFT_DBG_GLYPH32) | |||
| 190 | printf ("Set face size to %dx%d (%dx%d)\n", | |||
| 191 | (int) (xsize >> 6), (int) (ysize >> 6), (int) xsize, (int) ysize); | |||
| 192 | /* | |||
| 193 | * Bitmap only faces must match exactly, so find the closest | |||
| 194 | * one (height dominant search) | |||
| 195 | */ | |||
| 196 | if (!(face->face_flags & FT_FACE_FLAG_SCALABLE( 1L << 0 ))) | |||
| 197 | { | |||
| 198 | int i, best = 0; | |||
| 199 | ||||
| 200 | #define xft_abs(a)((a) < 0 ? -(a) : (a)) ((a) < 0 ? -(a) : (a)) | |||
| 201 | #define dist(a,b)((((a)-(b)) < 0 ? -((a)-(b)) : ((a)-(b)))) (xft_abs((a)-(b))(((a)-(b)) < 0 ? -((a)-(b)) : ((a)-(b)))) | |||
| 202 | ||||
| 203 | for (i = 1; i < face->num_fixed_sizes; i++) | |||
| 204 | { | |||
| 205 | if (dist (ysize, Y_SIZE(face,i))((((ysize)-(((face)->available_sizes[i].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[i].y_ppem))) : ((ysize )-(((face)->available_sizes[i].y_ppem))))) < | |||
| 206 | dist (ysize, Y_SIZE(face, best))((((ysize)-(((face)->available_sizes[best].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[best].y_ppem))) : ( (ysize)-(((face)->available_sizes[best].y_ppem))))) || | |||
| 207 | (dist (ysize, Y_SIZE(face, i))((((ysize)-(((face)->available_sizes[i].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[i].y_ppem))) : ((ysize )-(((face)->available_sizes[i].y_ppem))))) == | |||
| 208 | dist (ysize, Y_SIZE(face, best))((((ysize)-(((face)->available_sizes[best].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[best].y_ppem))) : ( (ysize)-(((face)->available_sizes[best].y_ppem))))) && | |||
| 209 | dist (xsize, X_SIZE(face, i))((((xsize)-(((face)->available_sizes[i].x_ppem))) < 0 ? -((xsize)-(((face)->available_sizes[i].x_ppem))) : ((xsize )-(((face)->available_sizes[i].x_ppem))))) < | |||
| 210 | dist (xsize, X_SIZE(face, best))((((xsize)-(((face)->available_sizes[best].x_ppem))) < 0 ? -((xsize)-(((face)->available_sizes[best].x_ppem))) : ( (xsize)-(((face)->available_sizes[best].x_ppem))))))) | |||
| 211 | { | |||
| 212 | best = i; | |||
| 213 | } | |||
| 214 | } | |||
| 215 | /* | |||
| 216 | * Freetype 2.1.7 and earlier used width/height | |||
| 217 | * for matching sizes in the BDF and PCF loaders. | |||
| 218 | * This has been fixed for 2.1.8. Because BDF and PCF | |||
| 219 | * files have but a single strike per file, we can | |||
| 220 | * simply try both sizes. | |||
| 221 | */ | |||
| 222 | if (FT_Set_Char_Size (face, face->available_sizes[best].x_ppem, | |||
| 223 | face->available_sizes[best].y_ppem, 0, 0) != 0 | |||
| 224 | && | |||
| 225 | FT_Set_Char_Size (face, face->available_sizes[best].width << 6, | |||
| 226 | face->available_sizes[best].height << 6, | |||
| 227 | 0, 0) != 0) | |||
| 228 | { | |||
| 229 | return False0; | |||
| 230 | } | |||
| 231 | } | |||
| 232 | else | |||
| 233 | { | |||
| 234 | if (FT_Set_Char_Size (face, xsize, ysize, 0, 0)) | |||
| 235 | { | |||
| 236 | return False0; | |||
| 237 | } | |||
| 238 | } | |||
| 239 | f->xsize = xsize; | |||
| 240 | f->ysize = ysize; | |||
| 241 | } | |||
| 242 | if (!FT_Matrix_Equal (&f->matrix, matrix)((&f->matrix)->xx == (matrix)->xx && (& f->matrix)->yy == (matrix)->yy && (&f-> matrix)->xy == (matrix)->xy && (&f->matrix )->yx == (matrix)->yx)) | |||
| 243 | { | |||
| 244 | if (XftDebug() & XFT_DBG_GLYPH32) | |||
| 245 | printf ("Set face matrix to (%g,%g,%g,%g)\n", | |||
| 246 | (double) matrix->xx / 0x10000, | |||
| 247 | (double) matrix->xy / 0x10000, | |||
| 248 | (double) matrix->yx / 0x10000, | |||
| 249 | (double) matrix->yy / 0x10000); | |||
| 250 | FT_Set_Transform (face, matrix, NULL((void*)0)); | |||
| 251 | f->matrix = *matrix; | |||
| 252 | } | |||
| 253 | return True1; | |||
| 254 | } | |||
| 255 | ||||
| 256 | static void | |||
| 257 | _XftReleaseFile (XftFtFile *f) | |||
| 258 | { | |||
| 259 | XftFtFile **prev; | |||
| 260 | ||||
| 261 | if (--f->ref != 0) | |||
| 262 | return; | |||
| 263 | if (f->lock) | |||
| 264 | _XftLockError ("Attempt to close locked file"); | |||
| 265 | if (f->file) | |||
| 266 | { | |||
| 267 | for (prev = &_XftFtFiles; *prev; prev = &(*prev)->next) | |||
| 268 | { | |||
| 269 | if (*prev == f) | |||
| 270 | { | |||
| 271 | *prev = f->next; | |||
| 272 | break; | |||
| 273 | } | |||
| 274 | } | |||
| 275 | if (f->face) | |||
| 276 | FT_Done_Face (f->face); | |||
| 277 | } | |||
| 278 | XftMemFree (XFT_MEM_FILE2, | |||
| 279 | sizeof (XftFtFile) + (f->file ? strlen (f->file) + 1 : 0)); | |||
| 280 | free (f); | |||
| 281 | } | |||
| 282 | ||||
| 283 | /* | |||
| 284 | * Find a prime larger than the minimum reasonable hash size | |||
| 285 | */ | |||
| 286 | ||||
| 287 | static FcChar32 | |||
| 288 | _XftSqrt (FcChar32 a) | |||
| 289 | { | |||
| 290 | FcChar32 l, h, m; | |||
| 291 | ||||
| 292 | l = 2; | |||
| 293 | h = a/2; | |||
| 294 | while ((h-l) > 1) | |||
| 295 | { | |||
| 296 | m = (h+l) >> 1; | |||
| 297 | if (m * m < a) | |||
| 298 | l = m; | |||
| 299 | else | |||
| 300 | h = m; | |||
| 301 | } | |||
| 302 | return h; | |||
| 303 | } | |||
| 304 | ||||
| 305 | static FcBool | |||
| 306 | _XftIsPrime (FcChar32 i) | |||
| 307 | { | |||
| 308 | FcChar32 l, t; | |||
| 309 | ||||
| 310 | if (i < 2) | |||
| 311 | return FcFalse0; | |||
| 312 | if ((i & 1) == 0) | |||
| 313 | { | |||
| 314 | if (i == 2) | |||
| 315 | return FcTrue1; | |||
| 316 | return FcFalse0; | |||
| 317 | } | |||
| 318 | l = _XftSqrt (i) + 1; | |||
| 319 | for (t = 3; t <= l; t += 2) | |||
| 320 | if (i % t == 0) | |||
| 321 | return FcFalse0; | |||
| 322 | return FcTrue1; | |||
| 323 | } | |||
| 324 | ||||
| 325 | static FcChar32 | |||
| 326 | _XftHashSize (FcChar32 num_unicode) | |||
| 327 | { | |||
| 328 | /* at least 31.25 % extra space */ | |||
| 329 | FcChar32 hash = num_unicode + (num_unicode >> 2) + (num_unicode >> 4); | |||
| 330 | ||||
| 331 | if ((hash & 1) == 0) | |||
| 332 | hash++; | |||
| 333 | while (!_XftIsPrime (hash)) | |||
| 334 | hash += 2; | |||
| 335 | return hash; | |||
| 336 | } | |||
| 337 | ||||
| 338 | _X_EXPORT__attribute__((visibility("default"))) FT_Face | |||
| 339 | XftLockFace (XftFont *public) | |||
| 340 | { | |||
| 341 | XftFontInt *font = (XftFontInt *) public; | |||
| 342 | XftFontInfo *fi = &font->info; | |||
| 343 | FT_Face face; | |||
| 344 | ||||
| 345 | face = _XftLockFile (fi->file); | |||
| ||||
| 346 | /* | |||
| 347 | * Make sure the face is usable at the requested size | |||
| 348 | */ | |||
| 349 | if (face && !_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix)) | |||
| 350 | { | |||
| 351 | _XftUnlockFile (fi->file); | |||
| 352 | face = NULL((void*)0); | |||
| 353 | } | |||
| 354 | return face; | |||
| 355 | } | |||
| 356 | ||||
| 357 | _X_EXPORT__attribute__((visibility("default"))) void | |||
| 358 | XftUnlockFace (XftFont *public) | |||
| 359 | { | |||
| 360 | XftFontInt *font = (XftFontInt *) public; | |||
| 361 | _XftUnlockFile (font->info.file); | |||
| 362 | } | |||
| 363 | ||||
| 364 | static FcBool | |||
| 365 | XftFontInfoFill (Display *dpy, _Xconstconst FcPattern *pattern, XftFontInfo *fi) | |||
| 366 | { | |||
| 367 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True1); | |||
| 368 | FcChar8 *filename; | |||
| 369 | int id; | |||
| 370 | double dsize; | |||
| 371 | double aspect; | |||
| 372 | FcMatrix *font_matrix; | |||
| 373 | FcBool hinting, vertical_layout, autohint, global_advance; | |||
| 374 | int hint_style; | |||
| 375 | FcChar32 hash, *hashp; | |||
| 376 | FT_Face face; | |||
| 377 | int nhash; | |||
| 378 | FcBool bitmap; | |||
| 379 | ||||
| 380 | if (!info) | |||
| 381 | return FcFalse0; | |||
| 382 | ||||
| 383 | /* | |||
| 384 | * Initialize the whole XftFontInfo so that padding doesn't interfere with | |||
| 385 | * hash or XftFontInfoEqual(). | |||
| 386 | */ | |||
| 387 | ||||
| 388 | memset (fi, '\0', sizeof(*fi))__builtin___memset_chk (fi, '\0', sizeof(*fi), __builtin_object_size (fi, 0)); | |||
| 389 | ||||
| 390 | /* | |||
| 391 | * Find the associated file | |||
| 392 | */ | |||
| 393 | switch (FcPatternGetString (pattern, FC_FILE"file", 0, &filename)) { | |||
| 394 | case FcResultNoMatch: | |||
| 395 | filename = NULL((void*)0); | |||
| 396 | break; | |||
| 397 | case FcResultMatch: | |||
| 398 | break; | |||
| 399 | default: | |||
| 400 | goto bail0; | |||
| 401 | } | |||
| 402 | ||||
| 403 | switch (FcPatternGetInteger (pattern, FC_INDEX"index", 0, &id)) { | |||
| 404 | case FcResultNoMatch: | |||
| 405 | id = 0; | |||
| 406 | break; | |||
| 407 | case FcResultMatch: | |||
| 408 | break; | |||
| 409 | default: | |||
| 410 | goto bail0; | |||
| 411 | } | |||
| 412 | ||||
| 413 | if (filename) | |||
| 414 | fi->file = _XftGetFile (filename, id); | |||
| 415 | else if (FcPatternGetFTFace (pattern, FC_FT_FACE"ftface", 0, &face) == FcResultMatch | |||
| 416 | && face) | |||
| 417 | fi->file = _XftGetFaceFile (face); | |||
| 418 | if (!fi->file) | |||
| 419 | goto bail0; | |||
| 420 | ||||
| 421 | /* | |||
| 422 | * Compute pixel size | |||
| 423 | */ | |||
| 424 | if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE"pixelsize", 0, &dsize) != FcResultMatch) | |||
| 425 | goto bail1; | |||
| 426 | ||||
| 427 | if (FcPatternGetDouble (pattern, FC_ASPECT"aspect", 0, &aspect) != FcResultMatch) | |||
| 428 | aspect = 1.0; | |||
| 429 | ||||
| 430 | fi->ysize = (FT_F26Dot6) (dsize * 64.0); | |||
| 431 | fi->xsize = (FT_F26Dot6) (dsize * aspect * 64.0); | |||
| 432 | ||||
| 433 | if (XftDebug() & XFT_DBG_OPEN1) | |||
| 434 | printf ("XftFontInfoFill: %s: %d (%g pixels)\n", | |||
| 435 | (filename ? filename : (FcChar8 *) "<none>"), id, dsize); | |||
| 436 | /* | |||
| 437 | * Get antialias value | |||
| 438 | */ | |||
| 439 | switch (FcPatternGetBool (pattern, FC_ANTIALIAS"antialias", 0, &fi->antialias)) { | |||
| 440 | case FcResultNoMatch: | |||
| 441 | fi->antialias = True1; | |||
| 442 | break; | |||
| 443 | case FcResultMatch: | |||
| 444 | break; | |||
| 445 | default: | |||
| 446 | goto bail1; | |||
| 447 | } | |||
| 448 | ||||
| 449 | /* | |||
| 450 | * Get rgba value | |||
| 451 | */ | |||
| 452 | switch (FcPatternGetInteger (pattern, FC_RGBA"rgba", 0, &fi->rgba)) { | |||
| 453 | case FcResultNoMatch: | |||
| 454 | fi->rgba = FC_RGBA_UNKNOWN0; | |||
| 455 | break; | |||
| 456 | case FcResultMatch: | |||
| 457 | break; | |||
| 458 | default: | |||
| 459 | goto bail1; | |||
| 460 | } | |||
| 461 | ||||
| 462 | /* | |||
| 463 | * Get lcd_filter value | |||
| 464 | */ | |||
| 465 | switch (FcPatternGetInteger (pattern, FC_LCD_FILTER"lcdfilter", 0, &fi->lcd_filter)) { | |||
| 466 | case FcResultNoMatch: | |||
| 467 | fi->lcd_filter = FC_LCD_DEFAULT1; | |||
| 468 | break; | |||
| 469 | case FcResultMatch: | |||
| 470 | break; | |||
| 471 | default: | |||
| 472 | goto bail1; | |||
| 473 | } | |||
| 474 | ||||
| 475 | /* | |||
| 476 | * Get matrix and transform values | |||
| 477 | */ | |||
| 478 | switch (FcPatternGetMatrix (pattern, FC_MATRIX"matrix", 0, &font_matrix)) { | |||
| 479 | case FcResultNoMatch: | |||
| 480 | fi->matrix.xx = fi->matrix.yy = 0x10000; | |||
| 481 | fi->matrix.xy = fi->matrix.yx = 0; | |||
| 482 | break; | |||
| 483 | case FcResultMatch: | |||
| 484 | fi->matrix.xx = 0x10000L * font_matrix->xx; | |||
| 485 | fi->matrix.yy = 0x10000L * font_matrix->yy; | |||
| 486 | fi->matrix.xy = 0x10000L * font_matrix->xy; | |||
| 487 | fi->matrix.yx = 0x10000L * font_matrix->yx; | |||
| 488 | break; | |||
| 489 | default: | |||
| 490 | goto bail1; | |||
| 491 | } | |||
| 492 | ||||
| 493 | fi->transform = (fi->matrix.xx != 0x10000 || fi->matrix.xy != 0 || | |||
| 494 | fi->matrix.yx != 0 || fi->matrix.yy != 0x10000); | |||
| 495 | ||||
| 496 | /* | |||
| 497 | * Get render value, set to false if no Render extension present | |||
| 498 | */ | |||
| 499 | if (info->hasRender) | |||
| 500 | { | |||
| 501 | switch (FcPatternGetBool (pattern, XFT_RENDER"render", 0, &fi->render)) { | |||
| 502 | case FcResultNoMatch: | |||
| 503 | fi->render = info->hasRender; | |||
| 504 | break; | |||
| 505 | case FcResultMatch: | |||
| 506 | break; | |||
| 507 | default: | |||
| 508 | goto bail1; | |||
| 509 | } | |||
| 510 | } | |||
| 511 | else | |||
| 512 | fi->render = FcFalse0; | |||
| 513 | ||||
| 514 | /* | |||
| 515 | * Compute glyph load flags | |||
| 516 | */ | |||
| 517 | fi->load_flags = FT_LOAD_DEFAULT0x0; | |||
| 518 | ||||
| 519 | #ifndef XFT_EMBEDDED_BITMAP"embeddedbitmap" | |||
| 520 | #define XFT_EMBEDDED_BITMAP"embeddedbitmap" "embeddedbitmap" | |||
| 521 | #endif | |||
| 522 | ||||
| 523 | switch (FcPatternGetBool (pattern, XFT_EMBEDDED_BITMAP"embeddedbitmap", 0, &bitmap)) { | |||
| 524 | case FcResultNoMatch: | |||
| 525 | bitmap = FcFalse0; | |||
| 526 | break; | |||
| 527 | case FcResultMatch: | |||
| 528 | break; | |||
| 529 | default: | |||
| 530 | goto bail1; | |||
| 531 | } | |||
| 532 | ||||
| 533 | /* disable bitmaps when anti-aliasing or transforming glyphs */ | |||
| 534 | if ((!bitmap && fi->antialias) || fi->transform) | |||
| 535 | fi->load_flags |= FT_LOAD_NO_BITMAP0x8; | |||
| 536 | ||||
| 537 | /* disable hinting if requested */ | |||
| 538 | switch (FcPatternGetBool (pattern, FC_HINTING"hinting", 0, &hinting)) { | |||
| 539 | case FcResultNoMatch: | |||
| 540 | hinting = FcTrue1; | |||
| 541 | break; | |||
| 542 | case FcResultMatch: | |||
| 543 | break; | |||
| 544 | default: | |||
| 545 | goto bail1; | |||
| 546 | } | |||
| 547 | ||||
| 548 | switch (FcPatternGetBool (pattern, FC_EMBOLDEN"embolden", 0, &fi->embolden)) { | |||
| 549 | case FcResultNoMatch: | |||
| 550 | fi->embolden = FcFalse0; | |||
| 551 | break; | |||
| 552 | case FcResultMatch: | |||
| 553 | break; | |||
| 554 | default: | |||
| 555 | goto bail1; | |||
| 556 | } | |||
| 557 | ||||
| 558 | switch (FcPatternGetInteger (pattern, FC_HINT_STYLE"hintstyle", 0, &hint_style)) { | |||
| 559 | case FcResultNoMatch: | |||
| 560 | hint_style = FC_HINT_FULL3; | |||
| 561 | break; | |||
| 562 | case FcResultMatch: | |||
| 563 | break; | |||
| 564 | default: | |||
| 565 | goto bail1; | |||
| 566 | } | |||
| 567 | ||||
| 568 | if (!hinting | |||
| 569 | || hint_style == FC_HINT_NONE0 | |||
| 570 | ) | |||
| 571 | { | |||
| 572 | fi->load_flags |= FT_LOAD_NO_HINTING0x2; | |||
| 573 | } | |||
| 574 | ||||
| 575 | /* Figure out the load target, which modifies the hinting | |||
| 576 | * behavior of FreeType based on the intended use of the glyphs. | |||
| 577 | */ | |||
| 578 | if (fi->antialias) | |||
| 579 | { | |||
| 580 | if (FC_HINT_NONE0 < hint_style && hint_style < FC_HINT_FULL3) | |||
| 581 | { | |||
| 582 | fi->load_flags |= FT_LOAD_TARGET_LIGHT( (FT_Int32)( (FT_RENDER_MODE_LIGHT) & 15 ) << 16 ); | |||
| 583 | } | |||
| 584 | else | |||
| 585 | { | |||
| 586 | /* autohinter will snap stems to integer widths, when | |||
| 587 | * the LCD targets are used. | |||
| 588 | */ | |||
| 589 | switch (fi->rgba) { | |||
| 590 | case FC_RGBA_RGB1: | |||
| 591 | case FC_RGBA_BGR2: | |||
| 592 | fi->load_flags |= FT_LOAD_TARGET_LCD( (FT_Int32)( (FT_RENDER_MODE_LCD) & 15 ) << 16 ); | |||
| 593 | break; | |||
| 594 | case FC_RGBA_VRGB3: | |||
| 595 | case FC_RGBA_VBGR4: | |||
| 596 | fi->load_flags |= FT_LOAD_TARGET_LCD_V( (FT_Int32)( (FT_RENDER_MODE_LCD_V) & 15 ) << 16 ); | |||
| 597 | break; | |||
| 598 | } | |||
| 599 | } | |||
| 600 | } | |||
| 601 | else | |||
| 602 | fi->load_flags |= FT_LOAD_TARGET_MONO( (FT_Int32)( (FT_RENDER_MODE_MONO) & 15 ) << 16 ); | |||
| 603 | ||||
| 604 | /* set vertical layout if requested */ | |||
| 605 | switch (FcPatternGetBool (pattern, FC_VERTICAL_LAYOUT"verticallayout", 0, &vertical_layout)) { | |||
| 606 | case FcResultNoMatch: | |||
| 607 | vertical_layout = FcFalse0; | |||
| 608 | break; | |||
| 609 | case FcResultMatch: | |||
| 610 | break; | |||
| 611 | default: | |||
| 612 | goto bail1; | |||
| 613 | } | |||
| 614 | ||||
| 615 | if (vertical_layout) | |||
| 616 | fi->load_flags |= FT_LOAD_VERTICAL_LAYOUT0x10; | |||
| 617 | ||||
| 618 | /* force autohinting if requested */ | |||
| 619 | switch (FcPatternGetBool (pattern, FC_AUTOHINT"autohint", 0, &autohint)) { | |||
| 620 | case FcResultNoMatch: | |||
| 621 | autohint = FcFalse0; | |||
| 622 | break; | |||
| 623 | case FcResultMatch: | |||
| 624 | break; | |||
| 625 | default: | |||
| 626 | goto bail1; | |||
| 627 | } | |||
| 628 | ||||
| 629 | if (autohint) | |||
| 630 | fi->load_flags |= FT_LOAD_FORCE_AUTOHINT0x20; | |||
| 631 | ||||
| 632 | /* disable global advance width (for broken DynaLab TT CJK fonts) */ | |||
| 633 | switch (FcPatternGetBool (pattern, FC_GLOBAL_ADVANCE"globaladvance", 0, &global_advance)) { | |||
| 634 | case FcResultNoMatch: | |||
| 635 | global_advance = FcTrue1; | |||
| 636 | break; | |||
| 637 | case FcResultMatch: | |||
| 638 | break; | |||
| 639 | default: | |||
| 640 | goto bail1; | |||
| 641 | } | |||
| 642 | ||||
| 643 | if (!global_advance) | |||
| 644 | fi->load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH0x200; | |||
| 645 | ||||
| 646 | /* | |||
| 647 | * Get requested spacing value | |||
| 648 | */ | |||
| 649 | switch (FcPatternGetInteger (pattern, FC_SPACING"spacing", 0, &fi->spacing)) { | |||
| 650 | case FcResultNoMatch: | |||
| 651 | fi->spacing = FC_PROPORTIONAL0; | |||
| 652 | break; | |||
| 653 | case FcResultMatch: | |||
| 654 | break; | |||
| 655 | default: | |||
| 656 | goto bail1; | |||
| 657 | } | |||
| 658 | ||||
| 659 | /* | |||
| 660 | * Check for minspace | |||
| 661 | */ | |||
| 662 | ||||
| 663 | switch (FcPatternGetBool (pattern, FC_MINSPACE"minspace", 0, &fi->minspace)) { | |||
| 664 | case FcResultNoMatch: | |||
| 665 | fi->minspace = FcFalse0; | |||
| 666 | break; | |||
| 667 | case FcResultMatch: | |||
| 668 | break; | |||
| 669 | default: | |||
| 670 | goto bail1; | |||
| 671 | } | |||
| 672 | /* | |||
| 673 | * Check for fixed pixel spacing | |||
| 674 | */ | |||
| 675 | switch (FcPatternGetInteger (pattern, FC_CHAR_WIDTH"charwidth", 0, &fi->char_width)) { | |||
| 676 | case FcResultNoMatch: | |||
| 677 | fi->char_width = 0; | |||
| 678 | break; | |||
| 679 | case FcResultMatch: | |||
| 680 | if (fi->char_width) | |||
| 681 | fi->spacing = FC_MONO100; | |||
| 682 | break; | |||
| 683 | default: | |||
| 684 | goto bail1; | |||
| 685 | } | |||
| 686 | ||||
| 687 | /* | |||
| 688 | * Step over hash value in the structure | |||
| 689 | */ | |||
| 690 | hash = 0; | |||
| 691 | hashp = (FcChar32 *) fi + 1; | |||
| 692 | nhash = (sizeof (XftFontInfo) / sizeof (FcChar32)) - 1; | |||
| 693 | ||||
| 694 | while (nhash--) | |||
| 695 | hash += *hashp++; | |||
| 696 | fi->hash = hash; | |||
| 697 | ||||
| 698 | /* | |||
| 699 | * All done | |||
| 700 | */ | |||
| 701 | return FcTrue1; | |||
| 702 | ||||
| 703 | bail1: | |||
| 704 | _XftReleaseFile (fi->file); | |||
| 705 | fi->file = NULL((void*)0); | |||
| 706 | bail0: | |||
| 707 | return FcFalse0; | |||
| 708 | } | |||
| 709 | ||||
| 710 | static void | |||
| 711 | XftFontInfoEmpty (Display *dpy, XftFontInfo *fi) | |||
| 712 | { | |||
| 713 | if (fi->file) | |||
| 714 | _XftReleaseFile (fi->file); | |||
| 715 | } | |||
| 716 | ||||
| 717 | XftFontInfo * | |||
| 718 | XftFontInfoCreate (Display *dpy, _Xconstconst FcPattern *pattern) | |||
| 719 | { | |||
| 720 | XftFontInfo *fi = malloc (sizeof (XftFontInfo)); | |||
| 721 | ||||
| 722 | if (!fi) | |||
| 723 | return NULL((void*)0); | |||
| 724 | ||||
| 725 | if (!XftFontInfoFill (dpy, pattern, fi)) | |||
| 726 | { | |||
| 727 | free (fi); | |||
| 728 | fi = NULL((void*)0); | |||
| 729 | } | |||
| 730 | XftMemAlloc (XFT_MEM_FONT1, sizeof (XftFontInfo)); | |||
| 731 | return fi; | |||
| 732 | } | |||
| 733 | ||||
| 734 | _X_EXPORT__attribute__((visibility("default"))) void | |||
| 735 | XftFontInfoDestroy (Display *dpy, XftFontInfo *fi) | |||
| 736 | { | |||
| 737 | XftFontInfoEmpty (dpy, fi); | |||
| 738 | XftMemFree (XFT_MEM_FONT1, sizeof (XftFontInfo)); | |||
| 739 | free (fi); | |||
| 740 | } | |||
| 741 | ||||
| 742 | _X_EXPORT__attribute__((visibility("default"))) FcChar32 | |||
| 743 | XftFontInfoHash (_Xconstconst XftFontInfo *fi) | |||
| 744 | { | |||
| 745 | return fi->hash; | |||
| 746 | } | |||
| 747 | ||||
| 748 | _X_EXPORT__attribute__((visibility("default"))) FcBool | |||
| 749 | XftFontInfoEqual (_Xconstconst XftFontInfo *a, _Xconstconst XftFontInfo *b) | |||
| 750 | { | |||
| 751 | return memcmp ((void *) a, (void *) b, sizeof (XftFontInfo)) == 0; | |||
| 752 | } | |||
| 753 | ||||
| 754 | _X_EXPORT__attribute__((visibility("default"))) XftFont * | |||
| 755 | XftFontOpenInfo (Display *dpy, | |||
| 756 | FcPattern *pattern, | |||
| 757 | XftFontInfo *fi) | |||
| 758 | { | |||
| 759 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True1); | |||
| 760 | FT_Face face; | |||
| 761 | XftFont **bucket; | |||
| 762 | XftFontInt *font; | |||
| 763 | XRenderPictFormat *format; | |||
| 764 | FcCharSet *charset; | |||
| 765 | FcChar32 num_unicode; | |||
| 766 | FcChar32 hash_value; | |||
| 767 | FcChar32 rehash_value; | |||
| 768 | FcBool antialias; | |||
| 769 | int max_glyph_memory; | |||
| 770 | int alloc_size; | |||
| 771 | int ascent, descent, height; | |||
| 772 | int i; | |||
| 773 | int num_glyphs; | |||
| 774 | ||||
| 775 | if (!info) | |||
| 776 | return NULL((void*)0); | |||
| 777 | /* | |||
| 778 | * Find a matching previously opened font | |||
| 779 | */ | |||
| 780 | bucket = &info->fontHash[fi->hash % XFT_NUM_FONT_HASH127]; | |||
| 781 | for (font = (XftFontInt *) *bucket; font; font = (XftFontInt *) font->hash_next) | |||
| 782 | if (XftFontInfoEqual (&font->info, fi)) | |||
| 783 | { | |||
| 784 | if (!font->ref++) | |||
| 785 | --info->num_unref_fonts; | |||
| 786 | FcPatternDestroy (pattern); | |||
| 787 | return &font->public; | |||
| 788 | } | |||
| 789 | ||||
| 790 | /* | |||
| 791 | * No existing font, create another. | |||
| 792 | */ | |||
| 793 | ||||
| 794 | if (XftDebug () & XFT_DBG_CACHE128) | |||
| 795 | printf ("New font %s/%d size %dx%d\n", | |||
| 796 | fi->file->file, fi->file->id, | |||
| 797 | (int) fi->xsize >> 6, (int) fi->ysize >> 6); | |||
| 798 | ||||
| 799 | if (FcPatternGetInteger (pattern, XFT_MAX_GLYPH_MEMORY"maxglyphmemory", 0, | |||
| 800 | &max_glyph_memory) != FcResultMatch) | |||
| 801 | max_glyph_memory = XFT_FONT_MAX_GLYPH_MEMORY(1024 * 1024); | |||
| 802 | ||||
| 803 | face = _XftLockFile (fi->file); | |||
| 804 | if (!face) | |||
| 805 | goto bail0; | |||
| 806 | ||||
| 807 | if (!_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix)) | |||
| 808 | goto bail1; | |||
| 809 | ||||
| 810 | /* | |||
| 811 | * Get the set of Unicode codepoints covered by the font. | |||
| 812 | * If the incoming pattern doesn't provide this data, go | |||
| 813 | * off and compute it. Yes, this is expensive, but it's | |||
| 814 | * required to map Unicode to glyph indices. | |||
| 815 | */ | |||
| 816 | if (FcPatternGetCharSet (pattern, FC_CHARSET"charset", 0, &charset) == FcResultMatch) | |||
| 817 | charset = FcCharSetCopy (charset); | |||
| 818 | else | |||
| 819 | charset = FcFreeTypeCharSet (face, FcConfigGetBlanks (NULL((void*)0))); | |||
| 820 | ||||
| 821 | antialias = fi->antialias; | |||
| 822 | if (!(face->face_flags & FT_FACE_FLAG_SCALABLE( 1L << 0 ))) | |||
| 823 | antialias = FcFalse0; | |||
| 824 | ||||
| 825 | /* | |||
| 826 | * Find the appropriate picture format | |||
| 827 | */ | |||
| 828 | if (fi->render) | |||
| 829 | { | |||
| 830 | if (antialias) | |||
| 831 | { | |||
| 832 | switch (fi->rgba) { | |||
| 833 | case FC_RGBA_RGB1: | |||
| 834 | case FC_RGBA_BGR2: | |||
| 835 | case FC_RGBA_VRGB3: | |||
| 836 | case FC_RGBA_VBGR4: | |||
| 837 | format = XRenderFindStandardFormat (dpy, PictStandardARGB320); | |||
| 838 | break; | |||
| 839 | default: | |||
| 840 | format = XRenderFindStandardFormat (dpy, PictStandardA82); | |||
| 841 | break; | |||
| 842 | } | |||
| 843 | } | |||
| 844 | else | |||
| 845 | { | |||
| 846 | format = XRenderFindStandardFormat (dpy, PictStandardA14); | |||
| 847 | } | |||
| 848 | ||||
| 849 | if (!format) | |||
| 850 | goto bail2; | |||
| 851 | } | |||
| 852 | else | |||
| 853 | format = NULL((void*)0); | |||
| 854 | ||||
| 855 | if (charset) | |||
| 856 | { | |||
| 857 | num_unicode = FcCharSetCount (charset); | |||
| 858 | hash_value = _XftHashSize (num_unicode); | |||
| 859 | rehash_value = hash_value - 2; | |||
| 860 | } | |||
| 861 | else | |||
| 862 | { | |||
| 863 | num_unicode = 0; | |||
| 864 | hash_value = 0; | |||
| 865 | rehash_value = 0; | |||
| 866 | } | |||
| 867 | ||||
| 868 | /* | |||
| 869 | * Sometimes the glyphs are numbered 1..n, other times 0..n-1, | |||
| 870 | * accept either numbering scheme by making room in the table | |||
| 871 | */ | |||
| 872 | num_glyphs = face->num_glyphs + 1; | |||
| 873 | alloc_size = (sizeof (XftFontInt) + | |||
| 874 | num_glyphs * sizeof (XftGlyph *) + | |||
| 875 | hash_value * sizeof (XftUcsHash)); | |||
| 876 | font = malloc (alloc_size); | |||
| 877 | ||||
| 878 | if (!font) | |||
| 879 | goto bail2; | |||
| 880 | ||||
| 881 | XftMemAlloc (XFT_MEM_FONT1, alloc_size); | |||
| 882 | ||||
| 883 | /* | |||
| 884 | * Public fields | |||
| 885 | */ | |||
| 886 | if (fi->transform) | |||
| 887 | { | |||
| 888 | FT_Vector vector; | |||
| 889 | ||||
| 890 | vector.x = 0; | |||
| 891 | vector.y = face->size->metrics.descender; | |||
| 892 | FT_Vector_Transform (&vector, &fi->matrix); | |||
| 893 | descent = -(vector.y >> 6); | |||
| 894 | ||||
| 895 | vector.x = 0; | |||
| 896 | vector.y = face->size->metrics.ascender; | |||
| 897 | FT_Vector_Transform (&vector, &fi->matrix); | |||
| 898 | ascent = vector.y >> 6; | |||
| 899 | ||||
| 900 | if (fi->minspace) | |||
| 901 | height = ascent + descent; | |||
| 902 | else | |||
| 903 | { | |||
| 904 | vector.x = 0; | |||
| 905 | vector.y = face->size->metrics.height; | |||
| 906 | FT_Vector_Transform (&vector, &fi->matrix); | |||
| 907 | height = vector.y >> 6; | |||
| 908 | } | |||
| 909 | } | |||
| 910 | else | |||
| 911 | { | |||
| 912 | descent = -(face->size->metrics.descender >> 6); | |||
| 913 | ascent = face->size->metrics.ascender >> 6; | |||
| 914 | if (fi->minspace) | |||
| 915 | height = ascent + descent; | |||
| 916 | else | |||
| 917 | height = face->size->metrics.height >> 6; | |||
| 918 | } | |||
| 919 | font->public.ascent = ascent; | |||
| 920 | font->public.descent = descent; | |||
| 921 | font->public.height = height; | |||
| 922 | ||||
| 923 | if (fi->char_width) | |||
| 924 | font->public.max_advance_width = fi->char_width; | |||
| 925 | else | |||
| 926 | { | |||
| 927 | if (fi->transform) | |||
| 928 | { | |||
| 929 | FT_Vector vector; | |||
| 930 | vector.x = face->size->metrics.max_advance; | |||
| 931 | vector.y = 0; | |||
| 932 | FT_Vector_Transform (&vector, &fi->matrix); | |||
| 933 | font->public.max_advance_width = vector.x >> 6; | |||
| 934 | } | |||
| 935 | else | |||
| 936 | font->public.max_advance_width = face->size->metrics.max_advance >> 6; | |||
| 937 | } | |||
| 938 | font->public.charset = charset; | |||
| 939 | font->public.pattern = pattern; | |||
| 940 | ||||
| 941 | /* | |||
| 942 | * Management fields | |||
| 943 | */ | |||
| 944 | font->ref = 1; | |||
| 945 | ||||
| 946 | font->next = info->fonts; | |||
| 947 | info->fonts = &font->public; | |||
| 948 | ||||
| 949 | font->hash_next = *bucket; | |||
| 950 | *bucket = &font->public; | |||
| 951 | ||||
| 952 | /* | |||
| 953 | * Copy the info over | |||
| 954 | */ | |||
| 955 | font->info = *fi; | |||
| 956 | /* | |||
| 957 | * reset the antialias field. It can't | |||
| 958 | * be set correctly until the font is opened, | |||
| 959 | * which doesn't happen in XftFontInfoFill | |||
| 960 | */ | |||
| 961 | font->info.antialias = antialias; | |||
| 962 | /* | |||
| 963 | * bump XftFile reference count | |||
| 964 | */ | |||
| 965 | font->info.file->ref++; | |||
| 966 | ||||
| 967 | /* | |||
| 968 | * Per glyph information | |||
| 969 | */ | |||
| 970 | font->glyphs = (XftGlyph **) (font + 1); | |||
| 971 | memset (font->glyphs, '\0', num_glyphs * sizeof (XftGlyph *))__builtin___memset_chk (font->glyphs, '\0', num_glyphs * sizeof (XftGlyph *), __builtin_object_size (font->glyphs, 0)); | |||
| 972 | font->num_glyphs = num_glyphs; | |||
| 973 | /* | |||
| 974 | * Unicode hash table information | |||
| 975 | */ | |||
| 976 | font->hash_table = (XftUcsHash *) (font->glyphs + font->num_glyphs); | |||
| 977 | for (i = 0; i < hash_value; i++) | |||
| 978 | { | |||
| 979 | font->hash_table[i].ucs4 = ((FcChar32) ~0); | |||
| 980 | font->hash_table[i].glyph = 0; | |||
| 981 | } | |||
| 982 | font->hash_value = hash_value; | |||
| 983 | font->rehash_value = rehash_value; | |||
| 984 | /* | |||
| 985 | * X specific fields | |||
| 986 | */ | |||
| 987 | font->glyphset = 0; | |||
| 988 | font->format = format; | |||
| 989 | ||||
| 990 | /* | |||
| 991 | * Glyph memory management fields | |||
| 992 | */ | |||
| 993 | font->glyph_memory = 0; | |||
| 994 | font->max_glyph_memory = max_glyph_memory; | |||
| 995 | font->use_free_glyphs = info->use_free_glyphs; | |||
| 996 | ||||
| 997 | _XftUnlockFile (fi->file); | |||
| 998 | ||||
| 999 | return &font->public; | |||
| 1000 | ||||
| 1001 | bail2: | |||
| 1002 | FcCharSetDestroy (charset); | |||
| 1003 | bail1: | |||
| 1004 | _XftUnlockFile (fi->file); | |||
| 1005 | bail0: | |||
| 1006 | return NULL((void*)0); | |||
| 1007 | } | |||
| 1008 | ||||
| 1009 | _X_EXPORT__attribute__((visibility("default"))) XftFont * | |||
| 1010 | XftFontOpenPattern (Display *dpy, FcPattern *pattern) | |||
| 1011 | { | |||
| 1012 | XftFontInfo info; | |||
| 1013 | XftFont *font; | |||
| 1014 | ||||
| 1015 | if (!XftFontInfoFill (dpy, pattern, &info)) | |||
| 1016 | return NULL((void*)0); | |||
| 1017 | ||||
| 1018 | font = XftFontOpenInfo (dpy, pattern, &info); | |||
| 1019 | XftFontInfoEmpty (dpy, &info); | |||
| 1020 | return font; | |||
| 1021 | } | |||
| 1022 | ||||
| 1023 | _X_EXPORT__attribute__((visibility("default"))) XftFont * | |||
| 1024 | XftFontCopy (Display *dpy, XftFont *public) | |||
| 1025 | { | |||
| 1026 | XftFontInt *font = (XftFontInt *) public; | |||
| 1027 | ||||
| 1028 | font->ref++; | |||
| 1029 | return public; | |||
| 1030 | } | |||
| 1031 | ||||
| 1032 | static void | |||
| 1033 | XftFontDestroy (Display *dpy, XftFont *public) | |||
| 1034 | { | |||
| 1035 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); | |||
| 1036 | XftFontInt *font = (XftFontInt *) public; | |||
| 1037 | int i; | |||
| 1038 | ||||
| 1039 | /* note reduction in memory use */ | |||
| 1040 | if (info) | |||
| 1041 | info->glyph_memory -= font->glyph_memory; | |||
| 1042 | /* Clean up the info */ | |||
| 1043 | XftFontInfoEmpty (dpy, &font->info); | |||
| 1044 | /* Free the glyphset */ | |||
| 1045 | if (font->glyphset) | |||
| 1046 | XRenderFreeGlyphSet (dpy, font->glyphset); | |||
| 1047 | /* Free the glyphs */ | |||
| 1048 | for (i = 0; i < font->num_glyphs; i++) | |||
| 1049 | { | |||
| 1050 | XftGlyph *xftg = font->glyphs[i]; | |||
| 1051 | if (xftg) | |||
| 1052 | { | |||
| 1053 | if (xftg->bitmap) | |||
| 1054 | free (xftg->bitmap); | |||
| 1055 | free (xftg); | |||
| 1056 | } | |||
| 1057 | } | |||
| 1058 | ||||
| 1059 | /* Free the pattern and the charset */ | |||
| 1060 | FcPatternDestroy (font->public.pattern); | |||
| 1061 | FcCharSetDestroy (font->public.charset); | |||
| 1062 | ||||
| 1063 | /* Finally, free the font structure */ | |||
| 1064 | XftMemFree (XFT_MEM_FONT1, sizeof (XftFontInt) + | |||
| 1065 | font->num_glyphs * sizeof (XftGlyph *) + | |||
| 1066 | font->hash_value * sizeof (XftUcsHash)); | |||
| 1067 | free (font); | |||
| 1068 | } | |||
| 1069 | ||||
| 1070 | static XftFont * | |||
| 1071 | XftFontFindNthUnref (XftDisplayInfo *info, int n) | |||
| 1072 | { | |||
| 1073 | XftFont *public; | |||
| 1074 | XftFontInt *font; | |||
| 1075 | ||||
| 1076 | for (public = info->fonts; public; public = font->next) | |||
| 1077 | { | |||
| 1078 | font = (XftFontInt*) public; | |||
| 1079 | if (!font->ref && !n--) | |||
| 1080 | break; | |||
| 1081 | } | |||
| 1082 | return public; | |||
| 1083 | } | |||
| 1084 | ||||
| 1085 | _X_HIDDEN__attribute__((visibility("hidden"))) void | |||
| 1086 | XftFontManageMemory (Display *dpy) | |||
| 1087 | { | |||
| 1088 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); | |||
| 1089 | XftFont **prev; | |||
| 1090 | XftFont *public; | |||
| 1091 | XftFontInt *font; | |||
| 1092 | ||||
| 1093 | if (!info) | |||
| 1094 | return; | |||
| 1095 | while (info->num_unref_fonts > info->max_unref_fonts) | |||
| 1096 | { | |||
| 1097 | public = XftFontFindNthUnref (info, rand() % info->num_unref_fonts); | |||
| 1098 | font = (XftFontInt *) public; | |||
| 1099 | ||||
| 1100 | if (XftDebug () & XFT_DBG_CACHE128) | |||
| 1101 | printf ("freeing unreferenced font %s/%d size %dx%d\n", | |||
| 1102 | font->info.file->file, font->info.file->id, | |||
| 1103 | (int) font->info.xsize >> 6, (int) font->info.ysize >> 6); | |||
| 1104 | ||||
| 1105 | /* Unhook from display list */ | |||
| 1106 | for (prev = &info->fonts; *prev; prev = &(*(XftFontInt **) prev)->next) | |||
| 1107 | { | |||
| 1108 | if (*prev == public) | |||
| 1109 | { | |||
| 1110 | *prev = font->next; | |||
| 1111 | break; | |||
| 1112 | } | |||
| 1113 | } | |||
| 1114 | /* Unhook from hash list */ | |||
| 1115 | for (prev = &info->fontHash[font->info.hash % XFT_NUM_FONT_HASH127]; | |||
| 1116 | *prev; | |||
| 1117 | prev = &(*(XftFontInt **) prev)->hash_next) | |||
| 1118 | { | |||
| 1119 | if (*prev == public) | |||
| 1120 | { | |||
| 1121 | *prev = font->hash_next; | |||
| 1122 | break; | |||
| 1123 | } | |||
| 1124 | } | |||
| 1125 | /* Destroy the font */ | |||
| 1126 | XftFontDestroy (dpy, public); | |||
| 1127 | --info->num_unref_fonts; | |||
| 1128 | } | |||
| 1129 | } | |||
| 1130 | ||||
| 1131 | _X_EXPORT__attribute__((visibility("default"))) void | |||
| 1132 | XftFontClose (Display *dpy, XftFont *public) | |||
| 1133 | { | |||
| 1134 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); | |||
| 1135 | XftFontInt *font = (XftFontInt *) public; | |||
| 1136 | ||||
| 1137 | if (--font->ref != 0) | |||
| 1138 | return; | |||
| 1139 | ||||
| 1140 | if (info) | |||
| 1141 | { | |||
| 1142 | ++info->num_unref_fonts; | |||
| 1143 | XftFontManageMemory (dpy); | |||
| 1144 | } | |||
| 1145 | else | |||
| 1146 | { | |||
| 1147 | XftFontDestroy (dpy, public); | |||
| 1148 | } | |||
| 1149 | } | |||
| 1150 | ||||
| 1151 | _X_EXPORT__attribute__((visibility("default"))) FcBool | |||
| 1152 | XftInitFtLibrary (void) | |||
| 1153 | { | |||
| 1154 | if (_XftFTlibrary) | |||
| 1155 | return FcTrue1; | |||
| 1156 | if (FT_Init_FreeType (&_XftFTlibrary)) | |||
| 1157 | return FcFalse0; | |||
| 1158 | return FcTrue1; | |||
| 1159 | } |