xftglyphs.c revision 0d590c07
1c76ae52dSmrg/* 2c76ae52dSmrg * Copyright © 2000 Keith Packard 3c76ae52dSmrg * 4c76ae52dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 5c76ae52dSmrg * documentation for any purpose is hereby granted without fee, provided that 6c76ae52dSmrg * the above copyright notice appear in all copies and that both that 7c76ae52dSmrg * copyright notice and this permission notice appear in supporting 8c76ae52dSmrg * documentation, and that the name of Keith Packard not be used in 9c76ae52dSmrg * advertising or publicity pertaining to distribution of the software without 10c76ae52dSmrg * specific, written prior permission. Keith Packard makes no 11c76ae52dSmrg * representations about the suitability of this software for any purpose. It 12c76ae52dSmrg * is provided "as is" without express or implied warranty. 13c76ae52dSmrg * 14c76ae52dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15c76ae52dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16c76ae52dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17c76ae52dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18c76ae52dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19c76ae52dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20c76ae52dSmrg * PERFORMANCE OF THIS SOFTWARE. 21c76ae52dSmrg */ 22c76ae52dSmrg 23c76ae52dSmrg#include "xftint.h" 24c76ae52dSmrg#include <freetype/ftoutln.h> 25c76ae52dSmrg 260d590c07Smrg#if HAVE_FT_GLYPHSLOT_EMBOLDEN 270d590c07Smrg#include <freetype/ftsynth.h> 280d590c07Smrg#endif 290d590c07Smrg 30c76ae52dSmrgstatic const int filters[3][3] = { 31c76ae52dSmrg /* red */ 32c76ae52dSmrg#if 0 33c76ae52dSmrg{ 65538*4/7,65538*2/7,65538*1/7 }, 34c76ae52dSmrg /* green */ 35c76ae52dSmrg{ 65536*1/4, 65536*2/4, 65537*1/4 }, 36c76ae52dSmrg /* blue */ 37c76ae52dSmrg{ 65538*1/7,65538*2/7,65538*4/7 }, 38c76ae52dSmrg#endif 39c76ae52dSmrg{ 65538*9/13,65538*3/13,65538*1/13 }, 40c76ae52dSmrg /* green */ 41c76ae52dSmrg{ 65538*1/6, 65538*4/6, 65538*1/6 }, 42c76ae52dSmrg /* blue */ 43c76ae52dSmrg{ 65538*1/13,65538*3/13,65538*9/13 }, 44c76ae52dSmrg}; 45c76ae52dSmrg 46c76ae52dSmrg/* 47c76ae52dSmrg * Validate the memory info for a font 48c76ae52dSmrg */ 49c76ae52dSmrg 50c76ae52dSmrgstatic void 51c76ae52dSmrg_XftFontValidateMemory (Display *dpy, XftFont *public) 52c76ae52dSmrg{ 53c76ae52dSmrg XftFontInt *font = (XftFontInt *) public; 54c76ae52dSmrg unsigned long glyph_memory; 55c76ae52dSmrg FT_UInt glyphindex; 56c76ae52dSmrg XftGlyph *xftg; 57c76ae52dSmrg 58c76ae52dSmrg glyph_memory = 0; 59c76ae52dSmrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 60c76ae52dSmrg { 61c76ae52dSmrg xftg = font->glyphs[glyphindex]; 62c76ae52dSmrg if (xftg) 63c76ae52dSmrg { 64c76ae52dSmrg glyph_memory += xftg->glyph_memory; 65c76ae52dSmrg } 66c76ae52dSmrg } 67c76ae52dSmrg if (glyph_memory != font->glyph_memory) 68c76ae52dSmrg printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n", 69c76ae52dSmrg font->glyph_memory, glyph_memory); 70c76ae52dSmrg} 71c76ae52dSmrg 72c76ae52dSmrg_X_EXPORT void 73c76ae52dSmrgXftFontLoadGlyphs (Display *dpy, 74c76ae52dSmrg XftFont *pub, 75c76ae52dSmrg FcBool need_bitmaps, 76c76ae52dSmrg _Xconst FT_UInt *glyphs, 77c76ae52dSmrg int nglyph) 78c76ae52dSmrg{ 79c76ae52dSmrg XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 80c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 81c76ae52dSmrg FT_Error error; 82c76ae52dSmrg FT_UInt glyphindex; 83c76ae52dSmrg FT_GlyphSlot glyphslot; 84c76ae52dSmrg XftGlyph *xftg; 85c76ae52dSmrg Glyph glyph; 86c76ae52dSmrg unsigned char bufLocal[4096]; 87c76ae52dSmrg unsigned char *bufBitmap = bufLocal; 88c76ae52dSmrg int bufSize = sizeof (bufLocal); 89c76ae52dSmrg int size, pitch; 90c76ae52dSmrg unsigned char bufLocalRgba[4096]; 91c76ae52dSmrg unsigned char *bufBitmapRgba = bufLocalRgba; 92c76ae52dSmrg int bufSizeRgba = sizeof (bufLocalRgba); 93c76ae52dSmrg int sizergba, pitchrgba, widthrgba; 94c76ae52dSmrg int width; 95c76ae52dSmrg int height; 96c76ae52dSmrg int left, right, top, bottom; 97c76ae52dSmrg int hmul = 1; 98c76ae52dSmrg int vmul = 1; 99c76ae52dSmrg FT_Bitmap ftbit; 100c76ae52dSmrg FT_Matrix matrix; 101c76ae52dSmrg FT_Vector vector; 102c76ae52dSmrg Bool subpixel = False; 103c76ae52dSmrg FT_Face face; 104c76ae52dSmrg 105c76ae52dSmrg if (!info) 106c76ae52dSmrg return; 107c76ae52dSmrg 108c76ae52dSmrg face = XftLockFace (&font->public); 109c76ae52dSmrg 110c76ae52dSmrg if (!face) 111c76ae52dSmrg return; 112c76ae52dSmrg 113c76ae52dSmrg matrix.xx = matrix.yy = 0x10000L; 114c76ae52dSmrg matrix.xy = matrix.yx = 0; 115c76ae52dSmrg 116c76ae52dSmrg if (font->info.antialias) 117c76ae52dSmrg { 118c76ae52dSmrg switch (font->info.rgba) { 119c76ae52dSmrg case FC_RGBA_RGB: 120c76ae52dSmrg case FC_RGBA_BGR: 121c76ae52dSmrg matrix.xx *= 3; 122c76ae52dSmrg subpixel = True; 123c76ae52dSmrg hmul = 3; 124c76ae52dSmrg break; 125c76ae52dSmrg case FC_RGBA_VRGB: 126c76ae52dSmrg case FC_RGBA_VBGR: 127c76ae52dSmrg matrix.yy *= 3; 128c76ae52dSmrg vmul = 3; 129c76ae52dSmrg subpixel = True; 130c76ae52dSmrg break; 131c76ae52dSmrg } 132c76ae52dSmrg } 133c76ae52dSmrg 134c76ae52dSmrg while (nglyph--) 135c76ae52dSmrg { 136c76ae52dSmrg glyphindex = *glyphs++; 137c76ae52dSmrg xftg = font->glyphs[glyphindex]; 138c76ae52dSmrg if (!xftg) 139c76ae52dSmrg continue; 140c76ae52dSmrg 141c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 142c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 143c76ae52dSmrg /* 144c76ae52dSmrg * Check to see if this glyph has just been loaded, 145c76ae52dSmrg * this happens when drawing the same glyph twice 146c76ae52dSmrg * in a single string 147c76ae52dSmrg */ 148c76ae52dSmrg if (xftg->glyph_memory) 149c76ae52dSmrg continue; 150c76ae52dSmrg 151c76ae52dSmrg error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); 152c76ae52dSmrg if (error) 153c76ae52dSmrg { 154c76ae52dSmrg /* 155c76ae52dSmrg * If anti-aliasing or transforming glyphs and 156c76ae52dSmrg * no outline version exists, fallback to the 157c76ae52dSmrg * bitmap and let things look bad instead of 158c76ae52dSmrg * missing the glyph 159c76ae52dSmrg */ 160c76ae52dSmrg if (font->info.load_flags & FT_LOAD_NO_BITMAP) 161c76ae52dSmrg error = FT_Load_Glyph (face, glyphindex, 162c76ae52dSmrg font->info.load_flags & ~FT_LOAD_NO_BITMAP); 163c76ae52dSmrg if (error) 164c76ae52dSmrg continue; 165c76ae52dSmrg } 166c76ae52dSmrg 167c76ae52dSmrg#define FLOOR(x) ((x) & -64) 168c76ae52dSmrg#define CEIL(x) (((x)+63) & -64) 169c76ae52dSmrg#define TRUNC(x) ((x) >> 6) 170c76ae52dSmrg#define ROUND(x) (((x)+32) & -64) 171c76ae52dSmrg 172c76ae52dSmrg glyphslot = face->glyph; 173c76ae52dSmrg 174c76ae52dSmrg#if HAVE_FT_GLYPHSLOT_EMBOLDEN 175c76ae52dSmrg /* 176c76ae52dSmrg * Embolden if required 177c76ae52dSmrg */ 178c76ae52dSmrg if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); 179c76ae52dSmrg#endif 180c76ae52dSmrg 181c76ae52dSmrg /* 182c76ae52dSmrg * Compute glyph metrics from FreeType information 183c76ae52dSmrg */ 184c76ae52dSmrg if(font->info.transform && glyphslot->format != ft_glyph_format_bitmap) 185c76ae52dSmrg { 186c76ae52dSmrg /* 187c76ae52dSmrg * calculate the true width by transforming all four corners. 188c76ae52dSmrg */ 189c76ae52dSmrg int xc, yc; 190c76ae52dSmrg left = right = top = bottom = 0; 191c76ae52dSmrg for(xc = 0; xc <= 1; xc ++) { 192c76ae52dSmrg for(yc = 0; yc <= 1; yc++) { 193c76ae52dSmrg vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; 194c76ae52dSmrg vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; 195c76ae52dSmrg FT_Vector_Transform(&vector, &font->info.matrix); 196c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 197c76ae52dSmrg printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 198c76ae52dSmrg (int) vector.x, (int) vector.y); 199c76ae52dSmrg if(xc == 0 && yc == 0) { 200c76ae52dSmrg left = right = vector.x; 201c76ae52dSmrg top = bottom = vector.y; 202c76ae52dSmrg } else { 203c76ae52dSmrg if(left > vector.x) left = vector.x; 204c76ae52dSmrg if(right < vector.x) right = vector.x; 205c76ae52dSmrg if(bottom > vector.y) bottom = vector.y; 206c76ae52dSmrg if(top < vector.y) top = vector.y; 207c76ae52dSmrg } 208c76ae52dSmrg 209c76ae52dSmrg } 210c76ae52dSmrg } 211c76ae52dSmrg left = FLOOR(left); 212c76ae52dSmrg right = CEIL(right); 213c76ae52dSmrg bottom = FLOOR(bottom); 214c76ae52dSmrg top = CEIL(top); 215c76ae52dSmrg 216c76ae52dSmrg } else { 217c76ae52dSmrg left = FLOOR( glyphslot->metrics.horiBearingX ); 218c76ae52dSmrg right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width ); 219c76ae52dSmrg 220c76ae52dSmrg top = CEIL( glyphslot->metrics.horiBearingY ); 221c76ae52dSmrg bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); 222c76ae52dSmrg } 223c76ae52dSmrg 224c76ae52dSmrg width = TRUNC(right - left); 225c76ae52dSmrg height = TRUNC( top - bottom ); 226c76ae52dSmrg 227c76ae52dSmrg /* 228c76ae52dSmrg * Clip charcell glyphs to the bounding box 229c76ae52dSmrg * XXX transformed? 230c76ae52dSmrg */ 231c76ae52dSmrg if (font->info.spacing >= FC_CHARCELL && !font->info.transform) 232c76ae52dSmrg { 233c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 234c76ae52dSmrg { 235c76ae52dSmrg if (TRUNC(bottom) > font->public.max_advance_width) 236c76ae52dSmrg { 237c76ae52dSmrg int adjust; 238c76ae52dSmrg 239c76ae52dSmrg adjust = bottom - (font->public.max_advance_width << 6); 240c76ae52dSmrg if (adjust > top) 241c76ae52dSmrg adjust = top; 242c76ae52dSmrg top -= adjust; 243c76ae52dSmrg bottom -= adjust; 244c76ae52dSmrg height = font->public.max_advance_width; 245c76ae52dSmrg } 246c76ae52dSmrg } 247c76ae52dSmrg else 248c76ae52dSmrg { 249c76ae52dSmrg if (TRUNC(right) > font->public.max_advance_width) 250c76ae52dSmrg { 251c76ae52dSmrg int adjust; 252c76ae52dSmrg 253c76ae52dSmrg adjust = right - (font->public.max_advance_width << 6); 254c76ae52dSmrg if (adjust > left) 255c76ae52dSmrg adjust = left; 256c76ae52dSmrg left -= adjust; 257c76ae52dSmrg right -= adjust; 258c76ae52dSmrg width = font->public.max_advance_width; 259c76ae52dSmrg } 260c76ae52dSmrg } 261c76ae52dSmrg } 262c76ae52dSmrg 263c76ae52dSmrg if (font->info.antialias) 264c76ae52dSmrg pitch = (width * hmul + 3) & ~3; 265c76ae52dSmrg else 266c76ae52dSmrg pitch = ((width + 31) & ~31) >> 3; 267c76ae52dSmrg 268c76ae52dSmrg size = pitch * height * vmul; 269c76ae52dSmrg 270c76ae52dSmrg xftg->metrics.width = width; 271c76ae52dSmrg xftg->metrics.height = height; 272c76ae52dSmrg xftg->metrics.x = -TRUNC(left); 273c76ae52dSmrg xftg->metrics.y = TRUNC(top); 274c76ae52dSmrg 275c76ae52dSmrg if (font->info.spacing >= FC_MONO) 276c76ae52dSmrg { 277c76ae52dSmrg if (font->info.transform) 278c76ae52dSmrg { 279c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 280c76ae52dSmrg { 281c76ae52dSmrg vector.x = 0; 282c76ae52dSmrg vector.y = -face->size->metrics.max_advance; 283c76ae52dSmrg } 284c76ae52dSmrg else 285c76ae52dSmrg { 286c76ae52dSmrg vector.x = face->size->metrics.max_advance; 287c76ae52dSmrg vector.y = 0; 288c76ae52dSmrg } 289c76ae52dSmrg FT_Vector_Transform (&vector, &font->info.matrix); 290c76ae52dSmrg xftg->metrics.xOff = vector.x >> 6; 291c76ae52dSmrg xftg->metrics.yOff = -(vector.y >> 6); 292c76ae52dSmrg } 293c76ae52dSmrg else 294c76ae52dSmrg { 295c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 296c76ae52dSmrg { 297c76ae52dSmrg xftg->metrics.xOff = 0; 298c76ae52dSmrg xftg->metrics.yOff = -font->public.max_advance_width; 299c76ae52dSmrg } 300c76ae52dSmrg else 301c76ae52dSmrg { 302c76ae52dSmrg xftg->metrics.xOff = font->public.max_advance_width; 303c76ae52dSmrg xftg->metrics.yOff = 0; 304c76ae52dSmrg } 305c76ae52dSmrg } 306c76ae52dSmrg } 307c76ae52dSmrg else 308c76ae52dSmrg { 309c76ae52dSmrg xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x)); 310c76ae52dSmrg xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y)); 311c76ae52dSmrg } 312c76ae52dSmrg 313c76ae52dSmrg /* 314c76ae52dSmrg * If the glyph is relatively large (> 1% of server memory), 315c76ae52dSmrg * don't send it until necessary 316c76ae52dSmrg */ 317c76ae52dSmrg if (!need_bitmaps && size > info->max_glyph_memory / 100) 318c76ae52dSmrg continue; 319c76ae52dSmrg 320c76ae52dSmrg /* 321c76ae52dSmrg * Make sure there's enough buffer space for the glyph 322c76ae52dSmrg */ 323c76ae52dSmrg if (size > bufSize) 324c76ae52dSmrg { 325c76ae52dSmrg if (bufBitmap != bufLocal) 326c76ae52dSmrg free (bufBitmap); 327c76ae52dSmrg bufBitmap = (unsigned char *) malloc (size); 328c76ae52dSmrg if (!bufBitmap) 329c76ae52dSmrg continue; 330c76ae52dSmrg bufSize = size; 331c76ae52dSmrg } 332c76ae52dSmrg memset (bufBitmap, 0, size); 333c76ae52dSmrg 334c76ae52dSmrg /* 335c76ae52dSmrg * Rasterize into the local buffer 336c76ae52dSmrg */ 337c76ae52dSmrg switch (glyphslot->format) { 338c76ae52dSmrg case ft_glyph_format_outline: 339c76ae52dSmrg ftbit.width = width * hmul; 340c76ae52dSmrg ftbit.rows = height * vmul; 341c76ae52dSmrg ftbit.pitch = pitch; 342c76ae52dSmrg if (font->info.antialias) 343c76ae52dSmrg ftbit.pixel_mode = ft_pixel_mode_grays; 344c76ae52dSmrg else 345c76ae52dSmrg ftbit.pixel_mode = ft_pixel_mode_mono; 346c76ae52dSmrg 347c76ae52dSmrg ftbit.buffer = bufBitmap; 348c76ae52dSmrg 349c76ae52dSmrg if (subpixel) 350c76ae52dSmrg FT_Outline_Transform (&glyphslot->outline, &matrix); 351c76ae52dSmrg 352c76ae52dSmrg FT_Outline_Translate ( &glyphslot->outline, -left*hmul, -bottom*vmul ); 353c76ae52dSmrg 354c76ae52dSmrg FT_Outline_Get_Bitmap( _XftFTlibrary, &glyphslot->outline, &ftbit ); 355c76ae52dSmrg break; 356c76ae52dSmrg case ft_glyph_format_bitmap: 357c76ae52dSmrg if (font->info.antialias) 358c76ae52dSmrg { 359c76ae52dSmrg unsigned char *srcLine, *dstLine; 360c76ae52dSmrg int height; 361c76ae52dSmrg int x; 362c76ae52dSmrg int h, v; 363c76ae52dSmrg 364c76ae52dSmrg srcLine = glyphslot->bitmap.buffer; 365c76ae52dSmrg dstLine = bufBitmap; 366c76ae52dSmrg height = glyphslot->bitmap.rows; 367c76ae52dSmrg while (height--) 368c76ae52dSmrg { 369c76ae52dSmrg for (x = 0; x < glyphslot->bitmap.width; x++) 370c76ae52dSmrg { 371c76ae52dSmrg /* always MSB bitmaps */ 372c76ae52dSmrg unsigned char a = ((srcLine[x >> 3] & (0x80 >> (x & 7))) ? 373c76ae52dSmrg 0xff : 0x00); 374c76ae52dSmrg if (subpixel) 375c76ae52dSmrg { 376c76ae52dSmrg for (v = 0; v < vmul; v++) 377c76ae52dSmrg for (h = 0; h < hmul; h++) 378c76ae52dSmrg dstLine[v * pitch + x*hmul + h] = a; 379c76ae52dSmrg } 380c76ae52dSmrg else 381c76ae52dSmrg dstLine[x] = a; 382c76ae52dSmrg } 383c76ae52dSmrg dstLine += pitch * vmul; 384c76ae52dSmrg srcLine += glyphslot->bitmap.pitch; 385c76ae52dSmrg } 386c76ae52dSmrg } 387c76ae52dSmrg else 388c76ae52dSmrg { 389c76ae52dSmrg unsigned char *srcLine, *dstLine; 390c76ae52dSmrg int h, bytes; 391c76ae52dSmrg 392c76ae52dSmrg srcLine = glyphslot->bitmap.buffer; 393c76ae52dSmrg dstLine = bufBitmap; 394c76ae52dSmrg h = glyphslot->bitmap.rows; 395c76ae52dSmrg bytes = (glyphslot->bitmap.width + 7) >> 3; 396c76ae52dSmrg while (h--) 397c76ae52dSmrg { 398c76ae52dSmrg memcpy (dstLine, srcLine, bytes); 399c76ae52dSmrg dstLine += pitch; 400c76ae52dSmrg srcLine += glyphslot->bitmap.pitch; 401c76ae52dSmrg } 402c76ae52dSmrg } 403c76ae52dSmrg break; 404c76ae52dSmrg default: 405c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 406c76ae52dSmrg printf ("glyph %d is not in a usable format\n", 407c76ae52dSmrg (int) glyphindex); 408c76ae52dSmrg continue; 409c76ae52dSmrg } 410c76ae52dSmrg 411c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 412c76ae52dSmrg { 413c76ae52dSmrg printf ("glyph %d:\n", (int) glyphindex); 414c76ae52dSmrg printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n", 415c76ae52dSmrg (int) glyphslot->metrics.horiBearingX, 416c76ae52dSmrg (int) glyphslot->metrics.horiBearingY, 417c76ae52dSmrg (int) glyphslot->metrics.width, 418c76ae52dSmrg (int) glyphslot->metrics.height, 419c76ae52dSmrg left, right, top, bottom, 420c76ae52dSmrg width, height); 421c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPHV) 422c76ae52dSmrg { 423c76ae52dSmrg int x, y; 424c76ae52dSmrg unsigned char *line; 425c76ae52dSmrg 426c76ae52dSmrg line = bufBitmap; 427c76ae52dSmrg for (y = 0; y < height * vmul; y++) 428c76ae52dSmrg { 429c76ae52dSmrg if (font->info.antialias) 430c76ae52dSmrg { 431c76ae52dSmrg static char den[] = { " .:;=+*#" }; 432c76ae52dSmrg for (x = 0; x < pitch; x++) 433c76ae52dSmrg printf ("%c", den[line[x] >> 5]); 434c76ae52dSmrg } 435c76ae52dSmrg else 436c76ae52dSmrg { 437c76ae52dSmrg for (x = 0; x < pitch * 8; x++) 438c76ae52dSmrg { 439c76ae52dSmrg printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' '); 440c76ae52dSmrg } 441c76ae52dSmrg } 442c76ae52dSmrg printf ("|\n"); 443c76ae52dSmrg line += pitch; 444c76ae52dSmrg } 445c76ae52dSmrg printf ("\n"); 446c76ae52dSmrg } 447c76ae52dSmrg } 448c76ae52dSmrg 449c76ae52dSmrg /* 450c76ae52dSmrg * Use the glyph index as the wire encoding; it 451c76ae52dSmrg * might be more efficient for some locales to map 452c76ae52dSmrg * these by first usage to smaller values, but that 453c76ae52dSmrg * would require persistently storing the map when 454c76ae52dSmrg * glyphs were freed. 455c76ae52dSmrg */ 456c76ae52dSmrg glyph = (Glyph) glyphindex; 457c76ae52dSmrg 458c76ae52dSmrg if (subpixel) 459c76ae52dSmrg { 460c76ae52dSmrg int x, y; 461c76ae52dSmrg unsigned char *in_line, *out_line, *in; 462c76ae52dSmrg unsigned int *out; 463c76ae52dSmrg unsigned int red, green, blue; 464c76ae52dSmrg int rf, gf, bf; 465c76ae52dSmrg int s; 466c76ae52dSmrg int o, os; 467c76ae52dSmrg 468c76ae52dSmrg /* 469c76ae52dSmrg * Filter the glyph to soften the color fringes 470c76ae52dSmrg */ 471c76ae52dSmrg widthrgba = width; 472c76ae52dSmrg pitchrgba = (widthrgba * 4 + 3) & ~3; 473c76ae52dSmrg sizergba = pitchrgba * height; 474c76ae52dSmrg 475c76ae52dSmrg os = 1; 476c76ae52dSmrg switch (font->info.rgba) { 477c76ae52dSmrg case FC_RGBA_VRGB: 478c76ae52dSmrg os = pitch; 479c76ae52dSmrg case FC_RGBA_RGB: 480c76ae52dSmrg default: 481c76ae52dSmrg rf = 0; 482c76ae52dSmrg gf = 1; 483c76ae52dSmrg bf = 2; 484c76ae52dSmrg break; 485c76ae52dSmrg case FC_RGBA_VBGR: 486c76ae52dSmrg os = pitch; 487c76ae52dSmrg case FC_RGBA_BGR: 488c76ae52dSmrg bf = 0; 489c76ae52dSmrg gf = 1; 490c76ae52dSmrg rf = 2; 491c76ae52dSmrg break; 492c76ae52dSmrg } 493c76ae52dSmrg if (sizergba > bufSizeRgba) 494c76ae52dSmrg { 495c76ae52dSmrg if (bufBitmapRgba != bufLocalRgba) 496c76ae52dSmrg free (bufBitmapRgba); 497c76ae52dSmrg bufBitmapRgba = (unsigned char *) malloc (sizergba); 498c76ae52dSmrg if (!bufBitmapRgba) 499c76ae52dSmrg continue; 500c76ae52dSmrg bufSizeRgba = sizergba; 501c76ae52dSmrg } 502c76ae52dSmrg memset (bufBitmapRgba, 0, sizergba); 503c76ae52dSmrg in_line = bufBitmap; 504c76ae52dSmrg out_line = bufBitmapRgba; 505c76ae52dSmrg for (y = 0; y < height; y++) 506c76ae52dSmrg { 507c76ae52dSmrg in = in_line; 508c76ae52dSmrg out = (unsigned int *) out_line; 509c76ae52dSmrg in_line += pitch * vmul; 510c76ae52dSmrg out_line += pitchrgba; 511c76ae52dSmrg for (x = 0; x < width * hmul; x += hmul) 512c76ae52dSmrg { 513c76ae52dSmrg red = green = blue = 0; 514c76ae52dSmrg o = 0; 515c76ae52dSmrg for (s = 0; s < 3; s++) 516c76ae52dSmrg { 517c76ae52dSmrg red += filters[rf][s]*in[x+o]; 518c76ae52dSmrg green += filters[gf][s]*in[x+o]; 519c76ae52dSmrg blue += filters[bf][s]*in[x+o]; 520c76ae52dSmrg o += os; 521c76ae52dSmrg } 522c76ae52dSmrg red = red / 65536; 523c76ae52dSmrg green = green / 65536; 524c76ae52dSmrg blue = blue / 65536; 525c76ae52dSmrg *out++ = (green << 24) | (red << 16) | (green << 8) | blue; 526c76ae52dSmrg } 527c76ae52dSmrg } 528c76ae52dSmrg 529c76ae52dSmrg xftg->glyph_memory = sizergba + sizeof (XftGlyph); 530c76ae52dSmrg if (font->format) 531c76ae52dSmrg { 532c76ae52dSmrg if (!font->glyphset) 533c76ae52dSmrg font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 534c76ae52dSmrg if (ImageByteOrder (dpy) != XftNativeByteOrder ()) 535c76ae52dSmrg XftSwapCARD32 ((CARD32 *) bufBitmapRgba, sizergba >> 2); 536c76ae52dSmrg XRenderAddGlyphs (dpy, font->glyphset, &glyph, 537c76ae52dSmrg &xftg->metrics, 1, 538c76ae52dSmrg (char *) bufBitmapRgba, sizergba); 539c76ae52dSmrg } 540c76ae52dSmrg else 541c76ae52dSmrg { 542c76ae52dSmrg if (sizergba) 543c76ae52dSmrg { 544c76ae52dSmrg xftg->bitmap = malloc (sizergba); 545c76ae52dSmrg if (xftg->bitmap) 546c76ae52dSmrg memcpy (xftg->bitmap, bufBitmapRgba, sizergba); 547c76ae52dSmrg } 548c76ae52dSmrg else 5490d590c07Smrg xftg->bitmap = NULL; 550c76ae52dSmrg } 551c76ae52dSmrg } 552c76ae52dSmrg else 553c76ae52dSmrg { 554c76ae52dSmrg xftg->glyph_memory = size + sizeof (XftGlyph); 555c76ae52dSmrg if (font->format) 556c76ae52dSmrg { 557c76ae52dSmrg /* 558c76ae52dSmrg * swap bit order around; FreeType is always MSBFirst 559c76ae52dSmrg */ 560c76ae52dSmrg if (!font->info.antialias) 561c76ae52dSmrg { 562c76ae52dSmrg if (BitmapBitOrder (dpy) != MSBFirst) 563c76ae52dSmrg { 564c76ae52dSmrg unsigned char *line; 565c76ae52dSmrg unsigned char c; 566c76ae52dSmrg int i; 567c76ae52dSmrg 568c76ae52dSmrg line = (unsigned char *) bufBitmap; 569c76ae52dSmrg i = size; 570c76ae52dSmrg while (i--) 571c76ae52dSmrg { 572c76ae52dSmrg c = *line; 573c76ae52dSmrg c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); 574c76ae52dSmrg c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); 575c76ae52dSmrg c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); 576c76ae52dSmrg *line++ = c; 577c76ae52dSmrg } 578c76ae52dSmrg } 579c76ae52dSmrg } 580c76ae52dSmrg if (!font->glyphset) 581c76ae52dSmrg font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 582c76ae52dSmrg XRenderAddGlyphs (dpy, font->glyphset, &glyph, 583c76ae52dSmrg &xftg->metrics, 1, 584c76ae52dSmrg (char *) bufBitmap, size); 585c76ae52dSmrg } 586c76ae52dSmrg else 587c76ae52dSmrg { 588c76ae52dSmrg if (size) 589c76ae52dSmrg { 590c76ae52dSmrg xftg->bitmap = malloc (size); 591c76ae52dSmrg if (xftg->bitmap) 592c76ae52dSmrg memcpy (xftg->bitmap, bufBitmap, size); 593c76ae52dSmrg } 594c76ae52dSmrg else 5950d590c07Smrg xftg->bitmap = NULL; 596c76ae52dSmrg } 597c76ae52dSmrg } 598c76ae52dSmrg font->glyph_memory += xftg->glyph_memory; 599c76ae52dSmrg info->glyph_memory += xftg->glyph_memory; 600c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 601c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 602c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHEV) 603c76ae52dSmrg printf ("Caching glyph 0x%x size %ld\n", glyphindex, 604c76ae52dSmrg xftg->glyph_memory); 605c76ae52dSmrg } 606c76ae52dSmrg if (bufBitmap != bufLocal) 607c76ae52dSmrg free (bufBitmap); 608c76ae52dSmrg if (bufBitmapRgba != bufLocalRgba) 609c76ae52dSmrg free (bufBitmapRgba); 610c76ae52dSmrg XftUnlockFace (&font->public); 611c76ae52dSmrg} 612c76ae52dSmrg 613c76ae52dSmrg_X_EXPORT void 614c76ae52dSmrgXftFontUnloadGlyphs (Display *dpy, 615c76ae52dSmrg XftFont *pub, 616c76ae52dSmrg _Xconst FT_UInt *glyphs, 617c76ae52dSmrg int nglyph) 618c76ae52dSmrg{ 619c76ae52dSmrg XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 620c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 621c76ae52dSmrg XftGlyph *xftg; 622c76ae52dSmrg FT_UInt glyphindex; 623c76ae52dSmrg Glyph glyphBuf[1024]; 624c76ae52dSmrg int nused; 625c76ae52dSmrg 626c76ae52dSmrg nused = 0; 627c76ae52dSmrg while (nglyph--) 628c76ae52dSmrg { 629c76ae52dSmrg glyphindex = *glyphs++; 630c76ae52dSmrg xftg = font->glyphs[glyphindex]; 631c76ae52dSmrg if (!xftg) 632c76ae52dSmrg continue; 633c76ae52dSmrg if (xftg->glyph_memory) 634c76ae52dSmrg { 635c76ae52dSmrg if (font->format) 636c76ae52dSmrg { 637c76ae52dSmrg if (font->glyphset) 638c76ae52dSmrg { 639c76ae52dSmrg glyphBuf[nused++] = (Glyph) glyphindex; 640c76ae52dSmrg if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) 641c76ae52dSmrg { 642c76ae52dSmrg XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 643c76ae52dSmrg nused = 0; 644c76ae52dSmrg } 645c76ae52dSmrg } 646c76ae52dSmrg } 647c76ae52dSmrg else 648c76ae52dSmrg { 649c76ae52dSmrg if (xftg->bitmap) 650c76ae52dSmrg free (xftg->bitmap); 651c76ae52dSmrg } 652c76ae52dSmrg font->glyph_memory -= xftg->glyph_memory; 653c76ae52dSmrg if (info) 654c76ae52dSmrg info->glyph_memory -= xftg->glyph_memory; 655c76ae52dSmrg } 656c76ae52dSmrg free (xftg); 657c76ae52dSmrg XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph)); 6580d590c07Smrg font->glyphs[glyphindex] = NULL; 659c76ae52dSmrg } 660c76ae52dSmrg if (font->glyphset && nused) 661c76ae52dSmrg XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 662c76ae52dSmrg} 663c76ae52dSmrg 664c76ae52dSmrg_X_EXPORT FcBool 665c76ae52dSmrgXftFontCheckGlyph (Display *dpy, 666c76ae52dSmrg XftFont *pub, 667c76ae52dSmrg FcBool need_bitmaps, 668c76ae52dSmrg FT_UInt glyph, 669c76ae52dSmrg FT_UInt *missing, 670c76ae52dSmrg int *nmissing) 671c76ae52dSmrg{ 672c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 673c76ae52dSmrg XftGlyph *xftg; 674c76ae52dSmrg int n; 675c76ae52dSmrg 676c76ae52dSmrg if (glyph >= font->num_glyphs) 677c76ae52dSmrg return FcFalse; 678c76ae52dSmrg xftg = font->glyphs[glyph]; 679c76ae52dSmrg if (!xftg || (need_bitmaps && !xftg->glyph_memory)) 680c76ae52dSmrg { 681c76ae52dSmrg if (!xftg) 682c76ae52dSmrg { 683c76ae52dSmrg xftg = (XftGlyph *) malloc (sizeof (XftGlyph)); 684c76ae52dSmrg if (!xftg) 685c76ae52dSmrg return FcFalse; 686c76ae52dSmrg XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph)); 6870d590c07Smrg xftg->bitmap = NULL; 688c76ae52dSmrg xftg->glyph_memory = 0; 689c76ae52dSmrg font->glyphs[glyph] = xftg; 690c76ae52dSmrg } 691c76ae52dSmrg n = *nmissing; 692c76ae52dSmrg missing[n++] = glyph; 693c76ae52dSmrg if (n == XFT_NMISSING) 694c76ae52dSmrg { 695c76ae52dSmrg XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); 696c76ae52dSmrg n = 0; 697c76ae52dSmrg } 698c76ae52dSmrg *nmissing = n; 699c76ae52dSmrg return FcTrue; 700c76ae52dSmrg } 701c76ae52dSmrg else 702c76ae52dSmrg return FcFalse; 703c76ae52dSmrg} 704c76ae52dSmrg 705c76ae52dSmrg_X_EXPORT FcBool 706c76ae52dSmrgXftCharExists (Display *dpy, 707c76ae52dSmrg XftFont *pub, 708c76ae52dSmrg FcChar32 ucs4) 709c76ae52dSmrg{ 710c76ae52dSmrg if (pub->charset) 711c76ae52dSmrg return FcCharSetHasChar (pub->charset, ucs4); 712c76ae52dSmrg return FcFalse; 713c76ae52dSmrg} 714c76ae52dSmrg 715c76ae52dSmrg#define Missing ((FT_UInt) ~0) 716c76ae52dSmrg 717c76ae52dSmrg_X_EXPORT FT_UInt 718c76ae52dSmrgXftCharIndex (Display *dpy, 719c76ae52dSmrg XftFont *pub, 720c76ae52dSmrg FcChar32 ucs4) 721c76ae52dSmrg{ 722c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 723c76ae52dSmrg FcChar32 ent, offset; 724c76ae52dSmrg FT_Face face; 725c76ae52dSmrg 726c76ae52dSmrg if (!font->hash_value) 727c76ae52dSmrg return 0; 728c76ae52dSmrg 729c76ae52dSmrg ent = ucs4 % font->hash_value; 730c76ae52dSmrg offset = 0; 731c76ae52dSmrg while (font->hash_table[ent].ucs4 != ucs4) 732c76ae52dSmrg { 733c76ae52dSmrg if (font->hash_table[ent].ucs4 == (FcChar32) ~0) 734c76ae52dSmrg { 735c76ae52dSmrg if (!XftCharExists (dpy, pub, ucs4)) 736c76ae52dSmrg return 0; 737c76ae52dSmrg face = XftLockFace (pub); 738c76ae52dSmrg if (!face) 739c76ae52dSmrg return 0; 740c76ae52dSmrg font->hash_table[ent].ucs4 = ucs4; 741c76ae52dSmrg font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); 742c76ae52dSmrg XftUnlockFace (pub); 743c76ae52dSmrg break; 744c76ae52dSmrg } 745c76ae52dSmrg if (!offset) 746c76ae52dSmrg { 747c76ae52dSmrg offset = ucs4 % font->rehash_value; 748c76ae52dSmrg if (!offset) 749c76ae52dSmrg offset = 1; 750c76ae52dSmrg } 751c76ae52dSmrg ent = ent + offset; 752c76ae52dSmrg if (ent >= font->hash_value) 753c76ae52dSmrg ent -= font->hash_value; 754c76ae52dSmrg } 755c76ae52dSmrg return font->hash_table[ent].glyph; 756c76ae52dSmrg} 757c76ae52dSmrg 758c76ae52dSmrg/* 759c76ae52dSmrg * Pick a random glyph from the font and remove it from the cache 760c76ae52dSmrg */ 761c76ae52dSmrg_X_HIDDEN void 762c76ae52dSmrg_XftFontUncacheGlyph (Display *dpy, XftFont *pub) 763c76ae52dSmrg{ 764c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 765c76ae52dSmrg unsigned long glyph_memory; 766c76ae52dSmrg FT_UInt glyphindex; 767c76ae52dSmrg XftGlyph *xftg; 768c76ae52dSmrg 769c76ae52dSmrg if (!font->glyph_memory) 770c76ae52dSmrg return; 771c76ae52dSmrg if (font->use_free_glyphs) 772c76ae52dSmrg { 773c76ae52dSmrg glyph_memory = rand() % font->glyph_memory; 774c76ae52dSmrg } 775c76ae52dSmrg else 776c76ae52dSmrg { 777c76ae52dSmrg if (font->glyphset) 778c76ae52dSmrg { 779c76ae52dSmrg XRenderFreeGlyphSet (dpy, font->glyphset); 780c76ae52dSmrg font->glyphset = 0; 781c76ae52dSmrg } 782c76ae52dSmrg glyph_memory = 0; 783c76ae52dSmrg } 784c76ae52dSmrg 785c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 786c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 787c76ae52dSmrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 788c76ae52dSmrg { 789c76ae52dSmrg xftg = font->glyphs[glyphindex]; 790c76ae52dSmrg if (xftg) 791c76ae52dSmrg { 792c76ae52dSmrg if (xftg->glyph_memory > glyph_memory) 793c76ae52dSmrg { 794c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHEV) 795c76ae52dSmrg printf ("Uncaching glyph 0x%x size %ld\n", 796c76ae52dSmrg glyphindex, xftg->glyph_memory); 797c76ae52dSmrg XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 798c76ae52dSmrg if (!font->use_free_glyphs) 799c76ae52dSmrg continue; 800c76ae52dSmrg break; 801c76ae52dSmrg } 802c76ae52dSmrg glyph_memory -= xftg->glyph_memory; 803c76ae52dSmrg } 804c76ae52dSmrg } 805c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 806c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 807c76ae52dSmrg} 808c76ae52dSmrg 809c76ae52dSmrg_X_HIDDEN void 810c76ae52dSmrg_XftFontManageMemory (Display *dpy, XftFont *pub) 811c76ae52dSmrg{ 812c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 813c76ae52dSmrg 814c76ae52dSmrg if (font->max_glyph_memory) 815c76ae52dSmrg { 816c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 817c76ae52dSmrg { 818c76ae52dSmrg if (font->glyph_memory > font->max_glyph_memory) 819c76ae52dSmrg printf ("Reduce memory for font 0x%lx from %ld to %ld\n", 820c76ae52dSmrg font->glyphset ? font->glyphset : (unsigned long) font, 821c76ae52dSmrg font->glyph_memory, font->max_glyph_memory); 822c76ae52dSmrg } 823c76ae52dSmrg while (font->glyph_memory > font->max_glyph_memory) 824c76ae52dSmrg _XftFontUncacheGlyph (dpy, pub); 825c76ae52dSmrg } 826c76ae52dSmrg _XftDisplayManageMemory (dpy); 827c76ae52dSmrg} 828