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