1c76ae52dSmrg/* 2120fad34Smrg * Copyright © 2022 Thomas E. Dickey 3c76ae52dSmrg * Copyright © 2000 Keith Packard 4c76ae52dSmrg * 5c76ae52dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 6c76ae52dSmrg * documentation for any purpose is hereby granted without fee, provided that 7120fad34Smrg * the above copyright notice appear in all copies and that both that copyright 8120fad34Smrg * notice and this permission notice appear in supporting documentation, and 9120fad34Smrg * that the name of the above copyright holders not be used in advertising or 10120fad34Smrg * publicity pertaining to distribution of the software without specific, 11120fad34Smrg * written prior permission. The above copyright holders make no 12c76ae52dSmrg * representations about the suitability of this software for any purpose. It 13c76ae52dSmrg * is provided "as is" without express or implied warranty. 14c76ae52dSmrg * 15120fad34Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO 16120fad34Smrg * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17120fad34Smrg * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE 18120fad34Smrg * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 19120fad34Smrg * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 20120fad34Smrg * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21120fad34Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22c76ae52dSmrg */ 23c76ae52dSmrg 24c76ae52dSmrg#include "xftint.h" 257bbb83baSmrg#include FT_OUTLINE_H 2612d4a5f4Smrg#include FT_LCD_FILTER_H 277bbb83baSmrg 2812d4a5f4Smrg#include FT_SYNTHESIS_H 29c76ae52dSmrg 30120fad34Smrg#include FT_GLYPH_H 31120fad34Smrg 32120fad34Smrgtypedef double m3x3[3][3]; 33120fad34Smrg 34120fad34Smrgstatic void 35120fad34Smrgm3x3_uniform(m3x3 m) 36120fad34Smrg{ 37120fad34Smrg m[0][0] = m[1][1] = m[2][2] = 1.0; 38120fad34Smrg m[0][1] = m[1][0] = m[0][2] = m[1][2] = m[2][0] = m[2][1] = 0; 39120fad34Smrg} 40120fad34Smrg 41120fad34Smrgstatic void 42120fad34Smrgm3x3_transform(FT_Vector *v, m3x3 m) 43120fad34Smrg{ 44120fad34Smrg double x, y; 45120fad34Smrg 46120fad34Smrg x = (double)v->x; 47120fad34Smrg y = (double)v->y; 48120fad34Smrg v->x = (FT_Pos)(x * m[0][0] + y * m[0][1] + m[0][2] + 0.5); 49120fad34Smrg v->y = (FT_Pos)(x * m[1][0] + y * m[1][1] + m[1][2] + 0.5); 50120fad34Smrg} 51120fad34Smrg 52120fad34Smrgstatic void 53120fad34Smrgm3x3_invert(m3x3 m, m3x3 mi) 54120fad34Smrg{ 55120fad34Smrg double det; 56120fad34Smrg 57120fad34Smrg det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]); 58120fad34Smrg det -= m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]); 59120fad34Smrg det += m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); 60120fad34Smrg det = 1.0 / det; 61120fad34Smrg mi[0][0] = det * (m[1][1] * m[2][2] - m[1][2] * m[2][1]); 62120fad34Smrg mi[1][0] = det * (m[1][2] * m[2][0] - m[1][0] * m[2][2]); 63120fad34Smrg mi[2][0] = det * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); 64120fad34Smrg mi[0][1] = det * (m[0][2] * m[2][1] - m[0][1] * m[2][2]); 65120fad34Smrg mi[1][1] = det * (m[0][0] * m[2][2] - m[0][2] * m[2][0]); 66120fad34Smrg mi[2][1] = det * (m[0][1] * m[2][0] - m[0][0] * m[2][1]); 67120fad34Smrg mi[0][2] = det * (m[0][1] * m[1][2] - m[0][2] * m[1][1]); 68120fad34Smrg mi[1][2] = det * (m[0][2] * m[1][0] - m[0][0] * m[1][2]); 69120fad34Smrg mi[2][2] = det * (m[0][0] * m[1][1] - m[0][1] * m[1][0]); 70120fad34Smrg} 71120fad34Smrg 72c76ae52dSmrg/* 73c76ae52dSmrg * Validate the memory info for a font 74c76ae52dSmrg */ 75c76ae52dSmrg 76c76ae52dSmrgstatic void 77120fad34Smrg_XftFontValidateMemory (Display *dpy _X_UNUSED, XftFont *public) 78c76ae52dSmrg{ 79c76ae52dSmrg XftFontInt *font = (XftFontInt *) public; 80c76ae52dSmrg unsigned long glyph_memory; 81c76ae52dSmrg FT_UInt glyphindex; 82c76ae52dSmrg XftGlyph *xftg; 83c76ae52dSmrg 84c76ae52dSmrg glyph_memory = 0; 85c76ae52dSmrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 86c76ae52dSmrg { 87c76ae52dSmrg xftg = font->glyphs[glyphindex]; 88c76ae52dSmrg if (xftg) 89c76ae52dSmrg { 90c76ae52dSmrg glyph_memory += xftg->glyph_memory; 91c76ae52dSmrg } 92c76ae52dSmrg } 93c76ae52dSmrg if (glyph_memory != font->glyph_memory) 94120fad34Smrg printf ("Font glyph cache incorrect has %lu bytes, should have %lu\n", 95c76ae52dSmrg font->glyph_memory, glyph_memory); 96c76ae52dSmrg} 97c76ae52dSmrg 98120fad34Smrg/* 99120fad34Smrg * Validate the glyph usage-links for a font. 100120fad34Smrg */ 101120fad34Smrgstatic void 102120fad34Smrg_XftValidateGlyphUsage(XftFontInt *font) 103120fad34Smrg{ 104120fad34Smrg if (font->newest != FT_UINT_MAX) { 105120fad34Smrg FT_UInt forward; 106120fad34Smrg FT_UInt reverse; 107120fad34Smrg FT_UInt next; 108120fad34Smrg XftGlyphUsage *x1st = (XftGlyphUsage *) font->glyphs[font->newest]; 109120fad34Smrg XftGlyphUsage *xuse = x1st; 110120fad34Smrg for (forward = 1, 111120fad34Smrg next = x1st->newer; 112120fad34Smrg xuse != NULL && 113120fad34Smrg next != font->newest; 114120fad34Smrg next = xuse->newer) { 115120fad34Smrg if (next >= font->num_glyphs) { 116120fad34Smrg printf("Xft: out of range; %d\n", next); 117120fad34Smrg break; 118120fad34Smrg } 119120fad34Smrg if (++forward > font->total_inuse) { 120120fad34Smrg printf("Xft: too many in-use glyphs (%d vs %d)\n", 121120fad34Smrg forward, font->total_inuse); 122120fad34Smrg if (forward > font->total_inuse + 10) 123120fad34Smrg break; 124120fad34Smrg } 125120fad34Smrg xuse = (XftGlyphUsage *) font->glyphs[next]; 126120fad34Smrg } 127120fad34Smrg if (forward < font->total_inuse) { 128120fad34Smrg printf("Xft: too few in-use glyphs (%u vs %d)\n", 129120fad34Smrg forward, font->total_inuse); 130120fad34Smrg } 131120fad34Smrg for (reverse = 1, 132120fad34Smrg next = x1st->older; 133120fad34Smrg xuse != NULL && 134120fad34Smrg next != font->newest; 135120fad34Smrg next = xuse->older) { 136120fad34Smrg if (next >= font->num_glyphs) { 137120fad34Smrg printf("Xft out of range; %d\n", next); 138120fad34Smrg break; 139120fad34Smrg } 140120fad34Smrg if (++reverse > font->total_inuse) { 141120fad34Smrg printf("Xft: too many in-use glyphs (%d vs %d)\n", 142120fad34Smrg reverse, font->total_inuse); 143120fad34Smrg if (reverse > font->total_inuse + 10) 144120fad34Smrg break; 145120fad34Smrg } 146120fad34Smrg xuse = (XftGlyphUsage *) font->glyphs[next]; 147120fad34Smrg } 148120fad34Smrg if (reverse < font->total_inuse) { 149120fad34Smrg printf("Xft: too few in-use glyphs (%u vs %d)\n", 150120fad34Smrg reverse, font->total_inuse); 151120fad34Smrg } 152120fad34Smrg if (forward != reverse) { 153120fad34Smrg printf("Xft: forward %d vs reverse %d\n", 154120fad34Smrg forward, reverse); 155120fad34Smrg exit(1); 156120fad34Smrg } 157120fad34Smrg } 158120fad34Smrg} 159120fad34Smrg 1602836776bSmrg/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot 1612836776bSmrg * into a different format. For example, we want to convert a 1622836776bSmrg * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit 1632836776bSmrg * ARGB or ABGR bitmap. 1642836776bSmrg * 1652836776bSmrg * this function prepares a target descriptor for this operation. 1662836776bSmrg * 1672836776bSmrg * input :: target bitmap descriptor. The function will set its 1682836776bSmrg * 'width', 'rows' and 'pitch' fields, and only these 1692836776bSmrg * 1702836776bSmrg * slot :: the glyph slot containing the source bitmap. this 1712836776bSmrg * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP 1722836776bSmrg * 1732836776bSmrg * mode :: the requested final rendering mode. supported values are 1742836776bSmrg * MONO, NORMAL (i.e. gray), LCD and LCD_V 1752836776bSmrg * 1762836776bSmrg * the function returns the size in bytes of the corresponding buffer, 1772836776bSmrg * it's up to the caller to allocate the corresponding memory block 1782836776bSmrg * before calling _fill_xrender_bitmap 1792836776bSmrg * 1802836776bSmrg * it also returns -1 in case of error (e.g. incompatible arguments, 1812836776bSmrg * like trying to convert a gray bitmap into a monochrome one) 1822836776bSmrg */ 1832836776bSmrgstatic int 1842836776bSmrg_compute_xrender_bitmap_size( FT_Bitmap* target, 1852836776bSmrg FT_GlyphSlot slot, 186120fad34Smrg FT_Render_Mode mode, 187120fad34Smrg FT_Matrix* matrix, 188120fad34Smrg m3x3 m ) 1892836776bSmrg{ 1902836776bSmrg FT_Bitmap* ftbit; 1912836776bSmrg int width, height, pitch; 1922836776bSmrg 1932836776bSmrg if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) 1942836776bSmrg return -1; 1952836776bSmrg 1960e0b1094Smrg /* compute the size of the final bitmap */ 1972836776bSmrg ftbit = &slot->bitmap; 1982836776bSmrg 1990e0b1094Smrg width = (int)ftbit->width; 2000e0b1094Smrg height = (int)ftbit->rows; 201120fad34Smrg 202120fad34Smrg if ( matrix && mode == FT_RENDER_MODE_NORMAL ) 203120fad34Smrg { 204120fad34Smrg FT_Matrix mirror, inverse; 205120fad34Smrg FT_Vector vector; 206120fad34Smrg int xc, yc; 207120fad34Smrg int left, right, top, bottom; 208120fad34Smrg 209120fad34Smrg left = right = top = bottom = 0; 210120fad34Smrg for (xc = 0; xc <= 1; xc++) { 211120fad34Smrg for (yc = 0; yc <= 1; yc++) { 212120fad34Smrg vector.x = xc * width; 213120fad34Smrg vector.y = yc * height; 214120fad34Smrg FT_Vector_Transform(&vector, matrix); 215120fad34Smrg if (xc == 0 && yc == 0) { 216120fad34Smrg left = right = (int)vector.x; 217120fad34Smrg top = bottom = (int)vector.y; 218120fad34Smrg } else { 219120fad34Smrg if (left > vector.x) left = (int)vector.x; 220120fad34Smrg if (right < vector.x) right = (int)vector.x; 221120fad34Smrg if (bottom > vector.y) bottom = (int)vector.y; 222120fad34Smrg if (top < vector.y) top = (int)vector.y; 223120fad34Smrg } 224120fad34Smrg } 225120fad34Smrg } 226120fad34Smrg width = (int)(right - left); 227120fad34Smrg height = (int)(top - bottom); 228120fad34Smrg 229120fad34Smrg mirror.xx = + 0x10000; 230120fad34Smrg mirror.yy = - 0x10000; 231120fad34Smrg mirror.xy = mirror.yx = 0; 232120fad34Smrg inverse = *matrix; 233120fad34Smrg FT_Matrix_Multiply(&mirror, &inverse); 234120fad34Smrg FT_Matrix_Invert(&inverse); 235120fad34Smrg FT_Matrix_Multiply(&mirror, &inverse); 236120fad34Smrg 237120fad34Smrg vector.x = vector.y = 0; 238120fad34Smrg FT_Vector_Transform(&vector, &inverse); 239120fad34Smrg left = (int)vector.x; 240120fad34Smrg bottom = (int)vector.y; 241120fad34Smrg vector.x = width; 242120fad34Smrg vector.y = height; 243120fad34Smrg FT_Vector_Transform(&vector, &inverse); 244120fad34Smrg right = (int)vector.x; 245120fad34Smrg top = (int)vector.y; 246120fad34Smrg left = (right - left) - (int)ftbit->width; 247120fad34Smrg bottom = (top - bottom) - (int)ftbit->rows; 248120fad34Smrg 249120fad34Smrg m[0][0] = (double)inverse.xx / 0x10000; 250120fad34Smrg m[0][1] = (double)inverse.xy / 0x10000; 251120fad34Smrg m[1][0] = (double)inverse.yx / 0x10000; 252120fad34Smrg m[1][1] = (double)inverse.yy / 0x10000; 253120fad34Smrg m[0][2] = (double)-left / 2; 254120fad34Smrg m[1][2] = (double)-bottom / 2; 255120fad34Smrg m[2][0] = m[2][1] = 0.0; 256120fad34Smrg m[2][2] = 1.0; 257120fad34Smrg } 2582836776bSmrg pitch = (width+3) & ~3; 2592836776bSmrg 2602836776bSmrg switch ( ftbit->pixel_mode ) 2612836776bSmrg { 2622836776bSmrg case FT_PIXEL_MODE_MONO: 2632836776bSmrg if ( mode == FT_RENDER_MODE_MONO ) 2642836776bSmrg { 2652836776bSmrg pitch = (((width+31) & ~31) >> 3); 2662836776bSmrg break; 2672836776bSmrg } 2682836776bSmrg /* fall-through */ 2692836776bSmrg 2702836776bSmrg case FT_PIXEL_MODE_GRAY: 2712836776bSmrg if ( mode == FT_RENDER_MODE_LCD || 2722836776bSmrg mode == FT_RENDER_MODE_LCD_V ) 2732836776bSmrg { 2742836776bSmrg /* each pixel is replicated into a 32-bit ARGB value */ 2752836776bSmrg pitch = width*4; 2762836776bSmrg } 2772836776bSmrg break; 2782836776bSmrg 279120fad34Smrg case FT_PIXEL_MODE_BGRA: 280120fad34Smrg pitch = width * 4; 281120fad34Smrg break; 282120fad34Smrg 2832836776bSmrg case FT_PIXEL_MODE_LCD: 2842836776bSmrg if ( mode != FT_RENDER_MODE_LCD ) 2852836776bSmrg return -1; 2862836776bSmrg 2872836776bSmrg /* horz pixel triplets are packed into 32-bit ARGB values */ 2882836776bSmrg width /= 3; 2892836776bSmrg pitch = width*4; 2902836776bSmrg break; 2912836776bSmrg 2922836776bSmrg case FT_PIXEL_MODE_LCD_V: 2932836776bSmrg if ( mode != FT_RENDER_MODE_LCD_V ) 2942836776bSmrg return -1; 2952836776bSmrg 2962836776bSmrg /* vert pixel triplets are packed into 32-bit ARGB values */ 2972836776bSmrg height /= 3; 2982836776bSmrg pitch = width*4; 2992836776bSmrg break; 3002836776bSmrg 3012836776bSmrg default: /* unsupported source format */ 3022836776bSmrg return -1; 3032836776bSmrg } 3042836776bSmrg 3050e0b1094Smrg target->width = (unsigned)width; 3060e0b1094Smrg target->rows = (unsigned)height; 3072836776bSmrg target->pitch = pitch; 3082836776bSmrg target->buffer = NULL; 3092836776bSmrg 3102836776bSmrg return pitch * height; 3112836776bSmrg} 3122836776bSmrg 313120fad34Smrg/* this functions converts the glyph bitmap found in a FT_GlyphSlot 314120fad34Smrg * into a different format while scaling by applying the given matrix 315120fad34Smrg * (see _compute_xrender_bitmap_size) 316120fad34Smrg * 317120fad34Smrg * you should call this function after _compute_xrender_bitmap_size 318120fad34Smrg * 319120fad34Smrg * target :: target bitmap descriptor. Note that its 'buffer' pointer 320120fad34Smrg * must point to memory allocated by the caller 321120fad34Smrg * 322120fad34Smrg * source :: the source bitmap descriptor 323120fad34Smrg * 324120fad34Smrg * matrix :: the scaling matrix to apply 325120fad34Smrg */ 326120fad34Smrgstatic void 327120fad34Smrg_scaled_fill_xrender_bitmap( FT_Bitmap* target, 328120fad34Smrg FT_Bitmap* source, 329120fad34Smrg m3x3 m ) 330120fad34Smrg{ 331120fad34Smrg unsigned char* src_buf = source->buffer; 332120fad34Smrg unsigned char* dst_line = target->buffer; 333120fad34Smrg int src_pitch = source->pitch; 334120fad34Smrg int width = (int) target->width; 335120fad34Smrg int height = (int) target->rows; 336120fad34Smrg int pitch = target->pitch; 337120fad34Smrg int i, x, y; 338120fad34Smrg FT_Vector vector, vector0; 339120fad34Smrg int sampling_width; 340120fad34Smrg int sampling_height; 341120fad34Smrg int sample_count; 342120fad34Smrg 343120fad34Smrg if ( src_pitch < 0 ) 344120fad34Smrg src_buf -= ((unsigned) src_pitch * (source->rows - 1)); 345120fad34Smrg 346120fad34Smrg /* compute how many source pixels a target pixel spans */ 347120fad34Smrg vector.x = 1; 348120fad34Smrg vector.y = 1; 349120fad34Smrg m3x3_transform(&vector, m); 350120fad34Smrg vector0.x = 0; 351120fad34Smrg vector0.y = 0; 352120fad34Smrg m3x3_transform(&vector0, m); 353120fad34Smrg sampling_width = (int) ((vector.x - vector0.x) / 2); 354120fad34Smrg sampling_height = (int) ((vector.y - vector0.y) / 2); 355120fad34Smrg if (sampling_width < 0) sampling_width = -sampling_width; 356120fad34Smrg if (sampling_height < 0) sampling_height = -sampling_height; 357120fad34Smrg sample_count = (2 * sampling_width + 1) * (2 * sampling_height + 1); 358120fad34Smrg 359120fad34Smrg for ( y = height; y > 0; y--, dst_line += pitch ) 360120fad34Smrg { 361120fad34Smrg for ( x = 0; x < width; x++ ) 362120fad34Smrg { 363120fad34Smrg unsigned char* src; 364120fad34Smrg 365120fad34Smrg /* compute target pixel location in source space */ 366120fad34Smrg vector.x = x; 367120fad34Smrg vector.y = height - y; 368120fad34Smrg m3x3_transform(&vector, m); 369120fad34Smrg 370120fad34Smrg if (source->pixel_mode == FT_PIXEL_MODE_BGRA) 371120fad34Smrg { 372120fad34Smrg if (vector.x < -sampling_width 373120fad34Smrg || vector.x > (source->width + (unsigned) sampling_width)) 374120fad34Smrg continue; 375120fad34Smrg if (vector.y < -sampling_height 376120fad34Smrg || vector.y > (source->rows + (unsigned) sampling_height)) 377120fad34Smrg continue; 378120fad34Smrg } 379120fad34Smrg else 380120fad34Smrg { 381120fad34Smrg if (vector.x < 0 || vector.x >= source->width) 382120fad34Smrg continue; 383120fad34Smrg if (vector.y < 0 || vector.y >= source->rows) 384120fad34Smrg continue; 385120fad34Smrg } 386120fad34Smrg 387120fad34Smrg switch ( source->pixel_mode ) 388120fad34Smrg { 389120fad34Smrg case FT_PIXEL_MODE_MONO: /* convert mono to 8-bit gray, scale using nearest pixel */ 390120fad34Smrg src = src_buf + (vector.y * src_pitch); 391120fad34Smrg if ( src[(vector.x >> 3)] & (0x80 >> (vector.x & 7)) ) 392120fad34Smrg dst_line[x] = 0xff; 393120fad34Smrg break; 394120fad34Smrg 395120fad34Smrg case FT_PIXEL_MODE_GRAY: /* scale using nearest pixel */ 396120fad34Smrg src = src_buf + (vector.y * src_pitch); 397120fad34Smrg dst_line[x] = src[vector.x]; 398120fad34Smrg break; 399120fad34Smrg 400120fad34Smrg case FT_PIXEL_MODE_BGRA: /* scale by averaging all relevant source pixels, keep BGRA format */ 401120fad34Smrg { 402120fad34Smrg int sample_x, sample_y; 403120fad34Smrg int bgra[4] = { 0, 0, 0, 0 }; 404120fad34Smrg 405120fad34Smrg for (sample_y = - sampling_height; sample_y < sampling_height + 1; ++sample_y) 406120fad34Smrg { 407120fad34Smrg int src_y = (int) (vector.y + sample_y); 408120fad34Smrg 409120fad34Smrg if (src_y < 0 || (FT_Pos) src_y >= source->rows) 410120fad34Smrg continue; 411120fad34Smrg src = src_buf + (src_y * src_pitch); 412120fad34Smrg for (sample_x = - sampling_width; sample_x < sampling_width + 1; ++sample_x) 413120fad34Smrg { 414120fad34Smrg int src_x = (int) (vector.x + sample_x); 415120fad34Smrg 416120fad34Smrg if (src_x < 0 || (FT_Pos) src_x >= source->width) 417120fad34Smrg continue; 418120fad34Smrg for (i = 0; i < 4; ++i) 419120fad34Smrg bgra[i] += src[src_x * 4 + i]; 420120fad34Smrg } 421120fad34Smrg } 422120fad34Smrg 423120fad34Smrg for (i = 0; i < 4; ++i) 424120fad34Smrg dst_line[4 * x + i] = (unsigned char) (bgra[i] / sample_count); 425120fad34Smrg break; 426120fad34Smrg } 427120fad34Smrg } 428120fad34Smrg } 429120fad34Smrg } 430120fad34Smrg} 431120fad34Smrg 4322836776bSmrg/* this functions converts the glyph bitmap found in a FT_GlyphSlot 4332836776bSmrg * into a different format (see _compute_xrender_bitmap_size) 4342836776bSmrg * 4352836776bSmrg * you should call this function after _compute_xrender_bitmap_size 4362836776bSmrg * 4372836776bSmrg * target :: target bitmap descriptor. Note that its 'buffer' pointer 4382836776bSmrg * must point to memory allocated by the caller 4392836776bSmrg * 4402836776bSmrg * slot :: the glyph slot containing the source bitmap 4412836776bSmrg * 4422836776bSmrg * mode :: the requested final rendering mode 4432836776bSmrg * 4442836776bSmrg * bgr :: boolean, set if BGR or VBGR pixel ordering is needed 4452836776bSmrg */ 4462836776bSmrgstatic void 4472836776bSmrg_fill_xrender_bitmap( FT_Bitmap* target, 4482836776bSmrg FT_GlyphSlot slot, 4492836776bSmrg FT_Render_Mode mode, 4502836776bSmrg int bgr ) 4512836776bSmrg{ 4522836776bSmrg FT_Bitmap* ftbit = &slot->bitmap; 4532836776bSmrg 4542836776bSmrg { 4552836776bSmrg unsigned char* srcLine = ftbit->buffer; 456120fad34Smrg unsigned char* dstLine = target->buffer; 457120fad34Smrg int src_pitch = ftbit->pitch; 458120fad34Smrg int width = (int)target->width; 459120fad34Smrg int height = (int)target->rows; 460120fad34Smrg int pitch = target->pitch; 461120fad34Smrg int subpixel; 462120fad34Smrg int h; 463120fad34Smrg 464120fad34Smrg subpixel = ( mode == FT_RENDER_MODE_LCD || 4652836776bSmrg mode == FT_RENDER_MODE_LCD_V ); 4662836776bSmrg 4672836776bSmrg if ( src_pitch < 0 ) 4680e0b1094Smrg srcLine -= ((unsigned)src_pitch * (ftbit->rows-1)); 4692836776bSmrg 4702836776bSmrg switch ( ftbit->pixel_mode ) 4712836776bSmrg { 4722836776bSmrg case FT_PIXEL_MODE_MONO: 4732836776bSmrg if ( subpixel ) /* convert mono to ARGB32 values */ 4742836776bSmrg { 4752836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 4762836776bSmrg { 4772836776bSmrg int x; 4782836776bSmrg 4792836776bSmrg for ( x = 0; x < width; x++ ) 4802836776bSmrg { 4812836776bSmrg if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 4822836776bSmrg ((unsigned int*)dstLine)[x] = 0xffffffffU; 4832836776bSmrg } 4842836776bSmrg } 4852836776bSmrg } 4862836776bSmrg else if ( mode == FT_RENDER_MODE_NORMAL ) /* convert mono to 8-bit gray */ 4872836776bSmrg { 4882836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 4892836776bSmrg { 4902836776bSmrg int x; 4912836776bSmrg 4922836776bSmrg for ( x = 0; x < width; x++ ) 4932836776bSmrg { 4942836776bSmrg if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) ) 4952836776bSmrg dstLine[x] = 0xff; 4962836776bSmrg } 4972836776bSmrg } 4982836776bSmrg } 4992836776bSmrg else /* copy mono to mono */ 5002836776bSmrg { 5012836776bSmrg int bytes = (width+7) >> 3; 5022836776bSmrg 5032836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 5040e0b1094Smrg memcpy( dstLine, srcLine, (size_t)bytes ); 5052836776bSmrg } 5062836776bSmrg break; 5072836776bSmrg 5082836776bSmrg case FT_PIXEL_MODE_GRAY: 5092836776bSmrg if ( subpixel ) /* convert gray to ARGB32 values */ 5102836776bSmrg { 5112836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 5122836776bSmrg { 5132836776bSmrg int x; 5142836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 5152836776bSmrg 5162836776bSmrg for ( x = 0; x < width; x++ ) 5172836776bSmrg { 5182836776bSmrg unsigned int pix = srcLine[x]; 5192836776bSmrg 5202836776bSmrg pix |= (pix << 8); 5212836776bSmrg pix |= (pix << 16); 5222836776bSmrg 5232836776bSmrg dst[x] = pix; 5242836776bSmrg } 5252836776bSmrg } 5262836776bSmrg } 5272836776bSmrg else /* copy gray into gray */ 5282836776bSmrg { 5292836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 5300e0b1094Smrg memcpy( dstLine, srcLine, (size_t)width ); 5312836776bSmrg } 5322836776bSmrg break; 5332836776bSmrg 534120fad34Smrg case FT_PIXEL_MODE_BGRA: /* Preserve BGRA format */ 535120fad34Smrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 536120fad34Smrg memcpy( dstLine, srcLine, (size_t) width * 4 ); 537120fad34Smrg break; 538120fad34Smrg 5392836776bSmrg case FT_PIXEL_MODE_LCD: 5402836776bSmrg if ( !bgr ) 5412836776bSmrg { 5422836776bSmrg /* convert horizontal RGB into ARGB32 */ 5432836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 5442836776bSmrg { 5452836776bSmrg int x; 5462836776bSmrg unsigned char* src = srcLine; 5472836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 5482836776bSmrg 5492836776bSmrg for ( x = 0; x < width; x++, src += 3 ) 5502836776bSmrg { 5512836776bSmrg unsigned int pix; 5522836776bSmrg 5532836776bSmrg pix = ((unsigned int)src[0] << 16) | 5542836776bSmrg ((unsigned int)src[1] << 8) | 5552836776bSmrg ((unsigned int)src[2] ) | 5562836776bSmrg ((unsigned int)src[1] << 24) ; 5572836776bSmrg 5582836776bSmrg dst[x] = pix; 5592836776bSmrg } 5602836776bSmrg } 5612836776bSmrg } 5622836776bSmrg else 5632836776bSmrg { 5642836776bSmrg /* convert horizontal BGR into ARGB32 */ 5652836776bSmrg for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) 5662836776bSmrg { 5672836776bSmrg int x; 5682836776bSmrg unsigned char* src = srcLine; 5692836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 5702836776bSmrg 5712836776bSmrg for ( x = 0; x < width; x++, src += 3 ) 5722836776bSmrg { 5732836776bSmrg unsigned int pix; 5742836776bSmrg 5752836776bSmrg pix = ((unsigned int)src[2] << 16) | 5762836776bSmrg ((unsigned int)src[1] << 8) | 5772836776bSmrg ((unsigned int)src[0] ) | 5782836776bSmrg ((unsigned int)src[1] << 24) ; 5792836776bSmrg 5802836776bSmrg dst[x] = pix; 5812836776bSmrg } 5822836776bSmrg } 5832836776bSmrg } 5842836776bSmrg break; 5852836776bSmrg 5862836776bSmrg default: /* FT_PIXEL_MODE_LCD_V */ 5872836776bSmrg /* convert vertical RGB into ARGB32 */ 5882836776bSmrg if ( !bgr ) 5892836776bSmrg { 5902836776bSmrg for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 5912836776bSmrg { 5922836776bSmrg int x; 5932836776bSmrg unsigned char* src = srcLine; 5942836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 5952836776bSmrg 5962836776bSmrg for ( x = 0; x < width; x++, src += 1 ) 5972836776bSmrg { 5982836776bSmrg unsigned int pix; 5992836776bSmrg 6002836776bSmrg pix = ((unsigned int)src[0] << 16) | 6012836776bSmrg ((unsigned int)src[src_pitch] << 8) | 6022836776bSmrg ((unsigned int)src[src_pitch*2] ) | 6032836776bSmrg ((unsigned int)src[src_pitch] << 24) ; 6042836776bSmrg 6052836776bSmrg dst[x] = pix; 6062836776bSmrg } 6072836776bSmrg } 6082836776bSmrg } 6092836776bSmrg else 6102836776bSmrg { 6112836776bSmrg for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch ) 6122836776bSmrg { 6132836776bSmrg int x; 6142836776bSmrg unsigned char* src = srcLine; 6152836776bSmrg unsigned int* dst = (unsigned int*)dstLine; 6162836776bSmrg 6172836776bSmrg for ( x = 0; x < width; x++, src += 1 ) 6182836776bSmrg { 6192836776bSmrg unsigned int pix; 6202836776bSmrg 6212836776bSmrg pix = ((unsigned int)src[src_pitch*2] << 16) | 6222836776bSmrg ((unsigned int)src[src_pitch] << 8) | 6232836776bSmrg ((unsigned int)src[0] ) | 6242836776bSmrg ((unsigned int)src[src_pitch] << 24) ; 6252836776bSmrg 6262836776bSmrg dst[x] = pix; 6272836776bSmrg } 6282836776bSmrg } 6292836776bSmrg } 6302836776bSmrg } 6312836776bSmrg } 6322836776bSmrg} 6332836776bSmrg 634c76ae52dSmrg_X_EXPORT void 635c76ae52dSmrgXftFontLoadGlyphs (Display *dpy, 636c76ae52dSmrg XftFont *pub, 637c76ae52dSmrg FcBool need_bitmaps, 638c76ae52dSmrg _Xconst FT_UInt *glyphs, 639c76ae52dSmrg int nglyph) 640c76ae52dSmrg{ 641c76ae52dSmrg XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 642c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 643c76ae52dSmrg FT_Error error; 644c76ae52dSmrg FT_UInt glyphindex; 645c76ae52dSmrg FT_GlyphSlot glyphslot; 646c76ae52dSmrg XftGlyph *xftg; 647c76ae52dSmrg Glyph glyph; 648c76ae52dSmrg unsigned char bufLocal[4096]; 649c76ae52dSmrg unsigned char *bufBitmap = bufLocal; 650c76ae52dSmrg int bufSize = sizeof (bufLocal); 6512836776bSmrg int size; 652c76ae52dSmrg int width; 653c76ae52dSmrg int height; 654c76ae52dSmrg int left, right, top, bottom; 6552836776bSmrg FT_Bitmap* ftbit; 6562836776bSmrg FT_Bitmap local; 657c76ae52dSmrg FT_Vector vector; 658120fad34Smrg m3x3 m; 659c76ae52dSmrg FT_Face face; 6602836776bSmrg FT_Render_Mode mode = FT_RENDER_MODE_MONO; 661120fad34Smrg FcBool transform; 662120fad34Smrg FcBool glyph_transform; 663c76ae52dSmrg 664c76ae52dSmrg if (!info) 665c76ae52dSmrg return; 666c76ae52dSmrg 667c76ae52dSmrg face = XftLockFace (&font->public); 6682836776bSmrg 669c76ae52dSmrg if (!face) 670c76ae52dSmrg return; 671c76ae52dSmrg 672120fad34Smrg if (font->info.color) 673120fad34Smrg mode = FT_RENDER_MODE_NORMAL; 674c76ae52dSmrg if (font->info.antialias) 675c76ae52dSmrg { 676c76ae52dSmrg switch (font->info.rgba) { 677c76ae52dSmrg case FC_RGBA_RGB: 678c76ae52dSmrg case FC_RGBA_BGR: 6792836776bSmrg mode = FT_RENDER_MODE_LCD; 680c76ae52dSmrg break; 681c76ae52dSmrg case FC_RGBA_VRGB: 682c76ae52dSmrg case FC_RGBA_VBGR: 6832836776bSmrg mode = FT_RENDER_MODE_LCD_V; 684c76ae52dSmrg break; 6852836776bSmrg default: 6862836776bSmrg mode = FT_RENDER_MODE_NORMAL; 687c76ae52dSmrg } 688c76ae52dSmrg } 689c76ae52dSmrg 690120fad34Smrg transform = font->info.transform && mode != FT_RENDER_MODE_MONO; 691120fad34Smrg 692c76ae52dSmrg while (nglyph--) 693c76ae52dSmrg { 694c76ae52dSmrg glyphindex = *glyphs++; 695c76ae52dSmrg xftg = font->glyphs[glyphindex]; 696c76ae52dSmrg if (!xftg) 697c76ae52dSmrg continue; 6982836776bSmrg 699c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 700c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 701c76ae52dSmrg /* 702c76ae52dSmrg * Check to see if this glyph has just been loaded, 703c76ae52dSmrg * this happens when drawing the same glyph twice 704c76ae52dSmrg * in a single string 705c76ae52dSmrg */ 706c76ae52dSmrg if (xftg->glyph_memory) 707c76ae52dSmrg continue; 7082836776bSmrg 7092836776bSmrg FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter); 7102836776bSmrg 711c76ae52dSmrg error = FT_Load_Glyph (face, glyphindex, font->info.load_flags); 712c76ae52dSmrg if (error) 713c76ae52dSmrg { 714c76ae52dSmrg /* 715c76ae52dSmrg * If anti-aliasing or transforming glyphs and 716c76ae52dSmrg * no outline version exists, fallback to the 717c76ae52dSmrg * bitmap and let things look bad instead of 718c76ae52dSmrg * missing the glyph 719c76ae52dSmrg */ 720c76ae52dSmrg if (font->info.load_flags & FT_LOAD_NO_BITMAP) 721c76ae52dSmrg error = FT_Load_Glyph (face, glyphindex, 722c76ae52dSmrg font->info.load_flags & ~FT_LOAD_NO_BITMAP); 723c76ae52dSmrg if (error) 724c76ae52dSmrg continue; 725c76ae52dSmrg } 726c76ae52dSmrg 727c76ae52dSmrg#define FLOOR(x) ((x) & -64) 728c76ae52dSmrg#define CEIL(x) (((x)+63) & -64) 729c76ae52dSmrg#define TRUNC(x) ((x) >> 6) 730c76ae52dSmrg#define ROUND(x) (((x)+32) & -64) 7312836776bSmrg 732c76ae52dSmrg glyphslot = face->glyph; 733c76ae52dSmrg 734c76ae52dSmrg /* 735c76ae52dSmrg * Embolden if required 736c76ae52dSmrg */ 737c76ae52dSmrg if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot); 738c76ae52dSmrg 739c76ae52dSmrg /* 740c76ae52dSmrg * Compute glyph metrics from FreeType information 741c76ae52dSmrg */ 742120fad34Smrg if (transform) 743c76ae52dSmrg { 744c76ae52dSmrg /* 745c76ae52dSmrg * calculate the true width by transforming all four corners. 746c76ae52dSmrg */ 747c76ae52dSmrg int xc, yc; 748c76ae52dSmrg left = right = top = bottom = 0; 749120fad34Smrg for (xc = 0; xc <= 1; xc++) { 750120fad34Smrg for (yc = 0; yc <= 1; yc++) { 751c76ae52dSmrg vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; 752c76ae52dSmrg vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; 7532836776bSmrg FT_Vector_Transform(&vector, &font->info.matrix); 754c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 7552836776bSmrg printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 756c76ae52dSmrg (int) vector.x, (int) vector.y); 757120fad34Smrg if (xc == 0 && yc == 0) { 7580e0b1094Smrg left = right = (int)vector.x; 7590e0b1094Smrg top = bottom = (int)vector.y; 760c76ae52dSmrg } else { 761120fad34Smrg if (left > vector.x) left = (int)vector.x; 762120fad34Smrg if (right < vector.x) right = (int)vector.x; 763120fad34Smrg if (bottom > vector.y) bottom = (int)vector.y; 764120fad34Smrg if (top < vector.y) top = (int)vector.y; 765c76ae52dSmrg } 766c76ae52dSmrg 767c76ae52dSmrg } 768c76ae52dSmrg } 7690e0b1094Smrg left = (int)FLOOR(left); 7700e0b1094Smrg right = (int)CEIL(right); 7710e0b1094Smrg bottom = (int)FLOOR(bottom); 772120fad34Smrg top = (int)CEIL(top); 773c76ae52dSmrg 774c76ae52dSmrg } else { 7750e0b1094Smrg left = (int)FLOOR( glyphslot->metrics.horiBearingX ); 7760e0b1094Smrg right = (int)CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width ); 777c76ae52dSmrg 7780e0b1094Smrg top = (int)CEIL( glyphslot->metrics.horiBearingY ); 7790e0b1094Smrg bottom = (int)FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); 780c76ae52dSmrg } 781c76ae52dSmrg 782c76ae52dSmrg /* 783c76ae52dSmrg * Clip charcell glyphs to the bounding box 784c76ae52dSmrg * XXX transformed? 785c76ae52dSmrg */ 786120fad34Smrg if (font->info.spacing >= FC_CHARCELL && !transform) 787c76ae52dSmrg { 788c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 789c76ae52dSmrg { 790c76ae52dSmrg if (TRUNC(bottom) > font->public.max_advance_width) 791c76ae52dSmrg { 792c76ae52dSmrg int adjust; 7932836776bSmrg 794c76ae52dSmrg adjust = bottom - (font->public.max_advance_width << 6); 795c76ae52dSmrg if (adjust > top) 796c76ae52dSmrg adjust = top; 797c76ae52dSmrg top -= adjust; 798c76ae52dSmrg bottom -= adjust; 799c76ae52dSmrg } 800c76ae52dSmrg } 801c76ae52dSmrg else 802c76ae52dSmrg { 803c76ae52dSmrg if (TRUNC(right) > font->public.max_advance_width) 804c76ae52dSmrg { 805c76ae52dSmrg int adjust; 8062836776bSmrg 807c76ae52dSmrg adjust = right - (font->public.max_advance_width << 6); 808c76ae52dSmrg if (adjust > left) 809c76ae52dSmrg adjust = left; 810c76ae52dSmrg left -= adjust; 811c76ae52dSmrg right -= adjust; 812c76ae52dSmrg } 813c76ae52dSmrg } 814c76ae52dSmrg } 815c76ae52dSmrg 816120fad34Smrg glyph_transform = transform; 8172836776bSmrg if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP ) 8182836776bSmrg { 8192836776bSmrg error = FT_Render_Glyph( face->glyph, mode ); 8202836776bSmrg if (error) 8212836776bSmrg continue; 822120fad34Smrg glyph_transform = False; 8232836776bSmrg } 824c76ae52dSmrg 8252836776bSmrg FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE ); 826c76ae52dSmrg 827c76ae52dSmrg if (font->info.spacing >= FC_MONO) 828c76ae52dSmrg { 829120fad34Smrg if (transform) 830c76ae52dSmrg { 831c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 832c76ae52dSmrg { 833c76ae52dSmrg vector.x = 0; 834c76ae52dSmrg vector.y = -face->size->metrics.max_advance; 835c76ae52dSmrg } 836c76ae52dSmrg else 837c76ae52dSmrg { 838c76ae52dSmrg vector.x = face->size->metrics.max_advance; 839c76ae52dSmrg vector.y = 0; 840c76ae52dSmrg } 841120fad34Smrg FT_Vector_Transform(&vector, &font->info.matrix); 842120fad34Smrg xftg->metrics.xOff = (short)(TRUNC(ROUND(vector.x))); 843a773ec55Smrg xftg->metrics.yOff = (short)(-TRUNC(ROUND(vector.y))); 844c76ae52dSmrg } 845c76ae52dSmrg else 846c76ae52dSmrg { 847a773ec55Smrg short maximum_x = (short)(font->public.max_advance_width); 848a773ec55Smrg short maximum_y = (short)(-font->public.max_advance_width); 849a773ec55Smrg short trimmed_x = (short)(TRUNC(ROUND(glyphslot->advance.x))); 850a773ec55Smrg short trimmed_y = (short)(-TRUNC(ROUND(glyphslot->advance.y))); 851c76ae52dSmrg if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) 852c76ae52dSmrg { 853c76ae52dSmrg xftg->metrics.xOff = 0; 854a773ec55Smrg xftg->metrics.yOff = min(maximum_y,trimmed_y); 855c76ae52dSmrg } 856c76ae52dSmrg else 857c76ae52dSmrg { 858a773ec55Smrg xftg->metrics.xOff = min(maximum_x,trimmed_x); 859c76ae52dSmrg xftg->metrics.yOff = 0; 860c76ae52dSmrg } 861c76ae52dSmrg } 862c76ae52dSmrg } 863c76ae52dSmrg else 864c76ae52dSmrg { 8650e0b1094Smrg xftg->metrics.xOff = (short)(TRUNC(ROUND(glyphslot->advance.x))); 8660e0b1094Smrg xftg->metrics.yOff = (short)(-TRUNC(ROUND(glyphslot->advance.y))); 867c76ae52dSmrg } 868c76ae52dSmrg 8690e0b1094Smrg /* compute the size of the final bitmap */ 8702836776bSmrg ftbit = &glyphslot->bitmap; 871c76ae52dSmrg 8720e0b1094Smrg width = (int)ftbit->width; 8730e0b1094Smrg height = (int)ftbit->rows; 874c76ae52dSmrg 875c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPH) 876c76ae52dSmrg { 877c76ae52dSmrg printf ("glyph %d:\n", (int) glyphindex); 878c76ae52dSmrg printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n", 879c76ae52dSmrg (int) glyphslot->metrics.horiBearingX, 880c76ae52dSmrg (int) glyphslot->metrics.horiBearingY, 881c76ae52dSmrg (int) glyphslot->metrics.width, 882c76ae52dSmrg (int) glyphslot->metrics.height, 883c76ae52dSmrg left, right, top, bottom, 884c76ae52dSmrg width, height); 885c76ae52dSmrg if (XftDebug() & XFT_DBG_GLYPHV) 886c76ae52dSmrg { 887c76ae52dSmrg int x, y; 888c76ae52dSmrg unsigned char *line; 889c76ae52dSmrg 8902836776bSmrg line = ftbit->buffer; 8912836776bSmrg if (ftbit->pitch < 0) 8922836776bSmrg line -= ftbit->pitch*(height-1); 8932836776bSmrg 8942836776bSmrg for (y = 0; y < height; y++) 895c76ae52dSmrg { 8962836776bSmrg if (font->info.antialias) 897c76ae52dSmrg { 8982836776bSmrg static const char den[] = { " .:;=+*#" }; 8992836776bSmrg for (x = 0; x < width; x++) 900c76ae52dSmrg printf ("%c", den[line[x] >> 5]); 901c76ae52dSmrg } 902c76ae52dSmrg else 903c76ae52dSmrg { 9042836776bSmrg for (x = 0; x < width * 8; x++) 905c76ae52dSmrg { 906120fad34Smrg printf ("%c", (line[x>>3] & (1 << (x & 7))) ? '#' : ' '); 907c76ae52dSmrg } 908c76ae52dSmrg } 909c76ae52dSmrg printf ("|\n"); 9102836776bSmrg line += ftbit->pitch; 911c76ae52dSmrg } 912c76ae52dSmrg printf ("\n"); 913c76ae52dSmrg } 914c76ae52dSmrg } 915c76ae52dSmrg 916120fad34Smrg m3x3_uniform(m); 917120fad34Smrg size = _compute_xrender_bitmap_size( &local, glyphslot, mode, glyph_transform ? &font->info.matrix : NULL, m ); 9182836776bSmrg if ( size < 0 ) 9192836776bSmrg continue; 9202836776bSmrg 9210e0b1094Smrg xftg->metrics.width = (unsigned short)local.width; 9220e0b1094Smrg xftg->metrics.height = (unsigned short)local.rows; 923120fad34Smrg if (glyph_transform) 924120fad34Smrg { 925120fad34Smrg m3x3 mi; 926120fad34Smrg 927120fad34Smrg m3x3_invert(m, mi); 928120fad34Smrg vector.x = - glyphslot->bitmap_left; 929120fad34Smrg vector.y = glyphslot->bitmap_top; 930120fad34Smrg m3x3_transform(&vector, mi); 931120fad34Smrg xftg->metrics.x = (short)vector.x; 932120fad34Smrg xftg->metrics.y = (short)vector.y; 933120fad34Smrg } 934120fad34Smrg else 935120fad34Smrg { 936120fad34Smrg xftg->metrics.x = (short)(- glyphslot->bitmap_left); 937120fad34Smrg xftg->metrics.y = (short)( glyphslot->bitmap_top); 938120fad34Smrg } 9392836776bSmrg 9402836776bSmrg /* 9412836776bSmrg * If the glyph is relatively large (> 1% of server memory), 9422836776bSmrg * don't send it until necessary. 9432836776bSmrg */ 944120fad34Smrg if (!need_bitmaps && ((unsigned long) size > (info->max_glyph_memory / 100))) 9452836776bSmrg continue; 9462836776bSmrg 9472836776bSmrg /* 9482836776bSmrg * Make sure there is enough buffer space for the glyph. 9492836776bSmrg */ 9502836776bSmrg if (size > bufSize) 9512836776bSmrg { 9522836776bSmrg if (bufBitmap != bufLocal) 9532836776bSmrg free (bufBitmap); 9540e0b1094Smrg bufBitmap = (unsigned char *) malloc ((size_t)size); 9552836776bSmrg if (!bufBitmap) 9562836776bSmrg continue; 9572836776bSmrg bufSize = size; 9582836776bSmrg } 9590e0b1094Smrg memset (bufBitmap, 0, (size_t)size); 9602836776bSmrg 9612836776bSmrg local.buffer = bufBitmap; 9622836776bSmrg 963120fad34Smrg if (mode == FT_RENDER_MODE_NORMAL && glyph_transform) 964120fad34Smrg _scaled_fill_xrender_bitmap(&local, &glyphslot->bitmap, m); 965120fad34Smrg else 966120fad34Smrg _fill_xrender_bitmap( &local, glyphslot, mode, 967120fad34Smrg (font->info.rgba == FC_RGBA_BGR || 968120fad34Smrg font->info.rgba == FC_RGBA_VBGR) ); 9692836776bSmrg 9702836776bSmrg /* 9712836776bSmrg * Copy or convert into local buffer. 9722836776bSmrg */ 9732836776bSmrg 974c76ae52dSmrg /* 975c76ae52dSmrg * Use the glyph index as the wire encoding; it 976c76ae52dSmrg * might be more efficient for some locales to map 977c76ae52dSmrg * these by first usage to smaller values, but that 978c76ae52dSmrg * would require persistently storing the map when 979c76ae52dSmrg * glyphs were freed. 980c76ae52dSmrg */ 981c76ae52dSmrg glyph = (Glyph) glyphindex; 982c76ae52dSmrg 983120fad34Smrg if (xftg->picture) 984120fad34Smrg { 985120fad34Smrg XRenderFreePicture(dpy, xftg->picture); 986120fad34Smrg xftg->picture = 0; 987120fad34Smrg } 988120fad34Smrg xftg->glyph_memory = (size_t)size + font->sizeof_glyph; 9892836776bSmrg if (font->format) 990c76ae52dSmrg { 9912836776bSmrg if (!font->glyphset) 9922836776bSmrg font->glyphset = XRenderCreateGlyphSet (dpy, font->format); 9932836776bSmrg if ( mode == FT_RENDER_MODE_MONO ) 994c76ae52dSmrg { 9952836776bSmrg /* swap bits in each byte */ 9962836776bSmrg if (BitmapBitOrder (dpy) != MSBFirst) 997c76ae52dSmrg { 9982836776bSmrg unsigned char *line = (unsigned char*)bufBitmap; 9992836776bSmrg int i = size; 10002836776bSmrg 10012836776bSmrg while (i--) 1002c76ae52dSmrg { 10032836776bSmrg int c = *line; 10042836776bSmrg c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55); 10052836776bSmrg c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33); 10062836776bSmrg c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f); 10070e0b1094Smrg *line++ = (unsigned char)c; 1008c76ae52dSmrg } 1009c76ae52dSmrg } 1010c76ae52dSmrg } 1011120fad34Smrg else if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA || mode != FT_RENDER_MODE_NORMAL) 1012c76ae52dSmrg { 10132836776bSmrg /* invert ARGB <=> BGRA */ 1014c76ae52dSmrg if (ImageByteOrder (dpy) != XftNativeByteOrder ()) 10152836776bSmrg XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2); 1016c76ae52dSmrg } 1017120fad34Smrg 1018120fad34Smrg if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) 1019120fad34Smrg { 1020120fad34Smrg Pixmap pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), local.width, local.rows, 32); 1021120fad34Smrg GC gc = XCreateGC(dpy, pixmap, 0, NULL); 1022120fad34Smrg XImage image = { 1023120fad34Smrg (int) local.width, (int) local.rows, 0, ZPixmap, (char *)bufBitmap, 1024120fad34Smrg dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32, 1025120fad34Smrg 32, (int) (local.width * 4 - (unsigned) local.pitch), 32, 1026120fad34Smrg 0, 0, 0, NULL, { NULL } 1027120fad34Smrg }; 1028120fad34Smrg 1029120fad34Smrg XInitImage(&image); 1030120fad34Smrg XPutImage(dpy, pixmap, gc, &image, 0, 0, 0, 0, local.width, local.rows); 1031120fad34Smrg xftg->picture = XRenderCreatePicture(dpy, pixmap, font->format, 0, NULL); 1032120fad34Smrg 1033120fad34Smrg XFreeGC(dpy, gc); 1034120fad34Smrg XFreePixmap(dpy, pixmap); 1035120fad34Smrg /* 1036120fad34Smrg * Record 256 times higher memory pressure for unrotated 1037120fad34Smrg * pictures, and maximum for rotated pictures. 1038120fad34Smrg */ 1039120fad34Smrg if (font->info.matrix.xy || font->info.matrix.yx) 1040120fad34Smrg xftg->glyph_memory += font->max_glyph_memory - (unsigned long) size; 1041120fad34Smrg else 1042120fad34Smrg xftg->glyph_memory += (size_t)size * 255; 1043120fad34Smrg } 1044120fad34Smrg else 1045120fad34Smrg XRenderAddGlyphs (dpy, font->glyphset, &glyph, 1046120fad34Smrg &xftg->metrics, 1, 1047120fad34Smrg (char *) bufBitmap, size); 1048c76ae52dSmrg } 1049c76ae52dSmrg else 1050c76ae52dSmrg { 10512836776bSmrg if (size) 1052c76ae52dSmrg { 10530e0b1094Smrg xftg->bitmap = malloc ((size_t)size); 10542836776bSmrg if (xftg->bitmap) 10550e0b1094Smrg memcpy (xftg->bitmap, bufBitmap, (size_t)size); 1056c76ae52dSmrg } 1057c76ae52dSmrg else 10582836776bSmrg xftg->bitmap = NULL; 1059c76ae52dSmrg } 10602836776bSmrg 1061c76ae52dSmrg font->glyph_memory += xftg->glyph_memory; 1062c76ae52dSmrg info->glyph_memory += xftg->glyph_memory; 1063c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 1064c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 1065c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHEV) 1066120fad34Smrg printf ("Caching glyph 0x%x size %lu\n", glyphindex, 1067c76ae52dSmrg xftg->glyph_memory); 1068120fad34Smrg 1069120fad34Smrg if (font->track_mem_usage) { 1070120fad34Smrg XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1071120fad34Smrg 1072120fad34Smrg if (font->newest == FT_UINT_MAX) { 1073120fad34Smrg xuse->older = glyphindex; 1074120fad34Smrg xuse->newer = glyphindex; 1075120fad34Smrg if (XftDebug() & XFT_DBG_USAGE) 1076120fad34Smrg printf("alloc %p -> %d: %p USE %d.%d\n", 1077120fad34Smrg (void *) font, glyphindex, 1078120fad34Smrg (void *) xuse, xuse->older, xuse->newer); 1079120fad34Smrg } else { 1080120fad34Smrg XftGlyphUsage *xnew; 1081120fad34Smrg XftGlyphUsage *xold; 1082120fad34Smrg 1083120fad34Smrg assert(font->glyphs[font->newest] != NULL); 1084120fad34Smrg xnew = (XftGlyphUsage *) font->glyphs[font->newest]; 1085120fad34Smrg 1086120fad34Smrg assert(font->glyphs[xnew->newer] != NULL); 1087120fad34Smrg xold = (XftGlyphUsage *) font->glyphs[xnew->newer]; 1088120fad34Smrg 1089120fad34Smrg xuse->older = font->newest; 1090120fad34Smrg xuse->newer = xnew->newer; 1091120fad34Smrg xnew->newer = glyphindex; 1092120fad34Smrg xold->older = glyphindex; 1093120fad34Smrg if (XftDebug() & XFT_DBG_USAGE) 1094120fad34Smrg printf("alloc %p -> %d: %p USE %d.%d, %p NEW %d.%d %p OLD %d.%d\n", 1095120fad34Smrg (void *) font, glyphindex, 1096120fad34Smrg (void *) xuse, xuse->older, xuse->newer, 1097120fad34Smrg (void *) xnew, xnew->older, xnew->newer, 1098120fad34Smrg (void *) xold, xold->older, xold->newer); 1099120fad34Smrg } 1100120fad34Smrg 1101120fad34Smrg font->newest = glyphindex; 1102120fad34Smrg font->total_inuse++; 1103120fad34Smrg if (XftDebug() & XFT_DBG_USAGE) 1104120fad34Smrg _XftValidateGlyphUsage(font); 1105120fad34Smrg } 1106c76ae52dSmrg } 1107c76ae52dSmrg if (bufBitmap != bufLocal) 1108c76ae52dSmrg free (bufBitmap); 1109c76ae52dSmrg XftUnlockFace (&font->public); 1110c76ae52dSmrg} 1111c76ae52dSmrg 1112c76ae52dSmrg_X_EXPORT void 1113c76ae52dSmrgXftFontUnloadGlyphs (Display *dpy, 1114c76ae52dSmrg XftFont *pub, 1115c76ae52dSmrg _Xconst FT_UInt *glyphs, 1116c76ae52dSmrg int nglyph) 1117c76ae52dSmrg{ 1118c76ae52dSmrg XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 1119c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 1120c76ae52dSmrg XftGlyph *xftg; 1121c76ae52dSmrg FT_UInt glyphindex; 1122c76ae52dSmrg Glyph glyphBuf[1024]; 1123c76ae52dSmrg int nused; 11242836776bSmrg 1125c76ae52dSmrg nused = 0; 1126c76ae52dSmrg while (nglyph--) 1127c76ae52dSmrg { 1128c76ae52dSmrg glyphindex = *glyphs++; 1129c76ae52dSmrg xftg = font->glyphs[glyphindex]; 1130c76ae52dSmrg if (!xftg) 1131c76ae52dSmrg continue; 1132c76ae52dSmrg if (xftg->glyph_memory) 1133c76ae52dSmrg { 1134120fad34Smrg if (XftDebug() & XFT_DBG_CACHEV) 1135120fad34Smrg printf ("Uncaching glyph 0x%x size %lu\n", 1136120fad34Smrg glyphindex, xftg->glyph_memory); 1137c76ae52dSmrg if (font->format) 1138c76ae52dSmrg { 1139120fad34Smrg if (xftg->picture) 1140120fad34Smrg XRenderFreePicture(dpy, xftg->picture); 1141120fad34Smrg else if (font->glyphset) 1142c76ae52dSmrg { 1143c76ae52dSmrg glyphBuf[nused++] = (Glyph) glyphindex; 1144c76ae52dSmrg if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) 1145c76ae52dSmrg { 1146c76ae52dSmrg XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 1147c76ae52dSmrg nused = 0; 1148c76ae52dSmrg } 1149c76ae52dSmrg } 1150c76ae52dSmrg } 1151120fad34Smrg else if (xftg->bitmap) 1152120fad34Smrg free (xftg->bitmap); 1153c76ae52dSmrg font->glyph_memory -= xftg->glyph_memory; 1154c76ae52dSmrg if (info) 1155c76ae52dSmrg info->glyph_memory -= xftg->glyph_memory; 1156c76ae52dSmrg } 1157120fad34Smrg 1158120fad34Smrg if (font->track_mem_usage) { 1159120fad34Smrg XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1160120fad34Smrg XftGlyphUsage *xtmp; 1161120fad34Smrg 1162120fad34Smrg if (XftDebug() & XFT_DBG_USAGE) 1163120fad34Smrg printf("free %p -> %p USE %d.%d\n", 1164120fad34Smrg (void *) font, (void *) xuse, xuse->older, xuse->newer); 1165120fad34Smrg 1166120fad34Smrg if (xuse->older != FT_UINT_MAX) { 1167120fad34Smrg xtmp = (XftGlyphUsage *) font->glyphs[xuse->older]; 1168120fad34Smrg if (xtmp != NULL) { 1169120fad34Smrg /* update link around to oldest glyph */ 1170120fad34Smrg xtmp->newer = xuse->newer; 1171120fad34Smrg } 1172120fad34Smrg if (font->newest == glyphindex) { 1173120fad34Smrg if (font->newest == xuse->older) 1174120fad34Smrg font->newest = FT_UINT_MAX; 1175120fad34Smrg else 1176120fad34Smrg font->newest = xuse->older; 1177120fad34Smrg } 1178120fad34Smrg } 1179120fad34Smrg if (xuse->newer != FT_UINT_MAX) { 1180120fad34Smrg xtmp = (XftGlyphUsage *) font->glyphs[xuse->newer]; 1181120fad34Smrg if (xtmp != NULL) { 1182120fad34Smrg /* update link around to newest glyph */ 1183120fad34Smrg xtmp->older = xuse->older; 1184120fad34Smrg } 1185120fad34Smrg } 1186120fad34Smrg if (font->total_inuse) { 1187120fad34Smrg font->total_inuse--; 1188120fad34Smrg } else { 1189120fad34Smrg fprintf (stderr, "Xft: glyph count error\n"); 1190120fad34Smrg } 1191120fad34Smrg if (XftDebug() & XFT_DBG_USAGE) 1192120fad34Smrg _XftValidateGlyphUsage(font); 1193120fad34Smrg } 1194120fad34Smrg 1195c76ae52dSmrg free (xftg); 1196120fad34Smrg XftMemFree (XFT_MEM_GLYPH, font->sizeof_glyph); 11970d590c07Smrg font->glyphs[glyphindex] = NULL; 11982836776bSmrg } 1199c76ae52dSmrg if (font->glyphset && nused) 1200c76ae52dSmrg XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused); 1201c76ae52dSmrg} 1202c76ae52dSmrg 1203c76ae52dSmrg_X_EXPORT FcBool 1204c76ae52dSmrgXftFontCheckGlyph (Display *dpy, 1205c76ae52dSmrg XftFont *pub, 1206c76ae52dSmrg FcBool need_bitmaps, 1207c76ae52dSmrg FT_UInt glyph, 1208c76ae52dSmrg FT_UInt *missing, 1209c76ae52dSmrg int *nmissing) 1210c76ae52dSmrg{ 1211c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 1212c76ae52dSmrg XftGlyph *xftg; 1213c76ae52dSmrg int n; 12142836776bSmrg 1215c76ae52dSmrg if (glyph >= font->num_glyphs) 1216c76ae52dSmrg return FcFalse; 1217c76ae52dSmrg xftg = font->glyphs[glyph]; 1218c76ae52dSmrg if (!xftg || (need_bitmaps && !xftg->glyph_memory)) 1219c76ae52dSmrg { 1220c76ae52dSmrg if (!xftg) 1221c76ae52dSmrg { 1222120fad34Smrg xftg = malloc (font->sizeof_glyph); 1223c76ae52dSmrg if (!xftg) 1224c76ae52dSmrg return FcFalse; 1225120fad34Smrg XftMemAlloc (XFT_MEM_GLYPH, font->sizeof_glyph); 1226120fad34Smrg 12270d590c07Smrg xftg->bitmap = NULL; 1228c76ae52dSmrg xftg->glyph_memory = 0; 1229120fad34Smrg xftg->picture = 0; 1230c76ae52dSmrg font->glyphs[glyph] = xftg; 1231120fad34Smrg 1232120fad34Smrg if (font->track_mem_usage) { 1233120fad34Smrg XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1234120fad34Smrg xuse->older = FT_UINT_MAX; 1235120fad34Smrg xuse->newer = FT_UINT_MAX; 1236120fad34Smrg } 1237c76ae52dSmrg } 1238c76ae52dSmrg n = *nmissing; 1239c76ae52dSmrg missing[n++] = glyph; 1240c76ae52dSmrg if (n == XFT_NMISSING) 1241c76ae52dSmrg { 1242c76ae52dSmrg XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n); 1243c76ae52dSmrg n = 0; 1244c76ae52dSmrg } 1245c76ae52dSmrg *nmissing = n; 1246c76ae52dSmrg return FcTrue; 1247c76ae52dSmrg } 1248120fad34Smrg 1249120fad34Smrg /* 1250120fad34Smrg * Make unloading faster by moving newly-referenced glyphs to the front 1251120fad34Smrg * of the list, leaving the less-used glyphs on the end. 1252a773ec55Smrg * 1253a773ec55Smrg * If the glyph is zero, the older/newer data may not have been set. 1254120fad34Smrg */ 1255a773ec55Smrg if (glyph != 0 1256a773ec55Smrg && font->track_mem_usage 1257120fad34Smrg && font->total_inuse > 10 1258120fad34Smrg && font->newest != FT_UINT_MAX 1259120fad34Smrg && font->newest != glyph) 1260120fad34Smrg { 1261120fad34Smrg XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; 1262120fad34Smrg XftGlyphUsage *xtmp = (XftGlyphUsage *) font->glyphs[font->newest]; 1263120fad34Smrg XftGlyphUsage *xold; 1264120fad34Smrg XftGlyphUsage *xnew; 1265120fad34Smrg 1266120fad34Smrg /* delink */ 1267120fad34Smrg xold = (XftGlyphUsage *) font->glyphs[xuse->older]; 1268120fad34Smrg xnew = (XftGlyphUsage *) font->glyphs[xuse->newer]; 1269120fad34Smrg assert(xold != NULL); 1270120fad34Smrg assert(xnew != NULL); 1271120fad34Smrg xold->newer = xuse->newer; 1272120fad34Smrg xnew->older = xuse->older; 1273120fad34Smrg 1274120fad34Smrg /* relink */ 1275120fad34Smrg xnew = (XftGlyphUsage *) font->glyphs[xtmp->newer]; 1276120fad34Smrg assert(xnew != NULL); 1277120fad34Smrg xnew->older = glyph; 1278120fad34Smrg xuse->older = font->newest; 1279120fad34Smrg xuse->newer = xtmp->newer; 1280120fad34Smrg xtmp->newer = glyph; 1281120fad34Smrg 1282120fad34Smrg font->newest = glyph; 1283120fad34Smrg } 1284120fad34Smrg return FcFalse; 1285c76ae52dSmrg} 1286c76ae52dSmrg 1287c76ae52dSmrg_X_EXPORT FcBool 1288120fad34SmrgXftCharExists (Display *dpy _X_UNUSED, 1289c76ae52dSmrg XftFont *pub, 1290120fad34Smrg FcChar32 ucs4) 1291c76ae52dSmrg{ 1292c76ae52dSmrg if (pub->charset) 1293c76ae52dSmrg return FcCharSetHasChar (pub->charset, ucs4); 1294c76ae52dSmrg return FcFalse; 1295c76ae52dSmrg} 1296c76ae52dSmrg 1297c76ae52dSmrg#define Missing ((FT_UInt) ~0) 1298c76ae52dSmrg 1299c76ae52dSmrg_X_EXPORT FT_UInt 13002836776bSmrgXftCharIndex (Display *dpy, 1301c76ae52dSmrg XftFont *pub, 1302c76ae52dSmrg FcChar32 ucs4) 1303c76ae52dSmrg{ 1304c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 1305c76ae52dSmrg FcChar32 ent, offset; 1306c76ae52dSmrg FT_Face face; 13072836776bSmrg 1308c76ae52dSmrg if (!font->hash_value) 1309c76ae52dSmrg return 0; 1310c76ae52dSmrg 13110e0b1094Smrg ent = ucs4 % (FcChar32)font->hash_value; 1312c76ae52dSmrg offset = 0; 1313c76ae52dSmrg while (font->hash_table[ent].ucs4 != ucs4) 1314c76ae52dSmrg { 1315c76ae52dSmrg if (font->hash_table[ent].ucs4 == (FcChar32) ~0) 1316c76ae52dSmrg { 1317c76ae52dSmrg if (!XftCharExists (dpy, pub, ucs4)) 1318c76ae52dSmrg return 0; 1319c76ae52dSmrg face = XftLockFace (pub); 1320c76ae52dSmrg if (!face) 1321c76ae52dSmrg return 0; 1322c76ae52dSmrg font->hash_table[ent].ucs4 = ucs4; 1323c76ae52dSmrg font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4); 1324c76ae52dSmrg XftUnlockFace (pub); 1325c76ae52dSmrg break; 1326c76ae52dSmrg } 1327c76ae52dSmrg if (!offset) 1328c76ae52dSmrg { 13290e0b1094Smrg offset = ucs4 % (FcChar32)font->rehash_value; 1330c76ae52dSmrg if (!offset) 1331c76ae52dSmrg offset = 1; 1332c76ae52dSmrg } 1333c76ae52dSmrg ent = ent + offset; 1334120fad34Smrg if (ent >= (FcChar32)font->hash_value) 13350e0b1094Smrg ent -= (FcChar32)font->hash_value; 1336c76ae52dSmrg } 1337c76ae52dSmrg return font->hash_table[ent].glyph; 1338c76ae52dSmrg} 1339c76ae52dSmrg 1340c76ae52dSmrg/* 1341120fad34Smrg * Remove glyph(s) from the font to reduce memory-usage. 1342c76ae52dSmrg */ 1343c76ae52dSmrg_X_HIDDEN void 1344c76ae52dSmrg_XftFontUncacheGlyph (Display *dpy, XftFont *pub) 1345c76ae52dSmrg{ 1346c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 1347c76ae52dSmrg unsigned long glyph_memory; 1348c76ae52dSmrg FT_UInt glyphindex; 1349c76ae52dSmrg XftGlyph *xftg; 13502836776bSmrg 1351c76ae52dSmrg if (!font->glyph_memory) 1352c76ae52dSmrg return; 1353120fad34Smrg 1354120fad34Smrg if (XftDebug() & XFT_DBG_CACHE) 1355120fad34Smrg _XftFontValidateMemory (dpy, pub); 1356120fad34Smrg 1357120fad34Smrg if (font->track_mem_usage) 1358c76ae52dSmrg { 1359120fad34Smrg /* 1360120fad34Smrg * Remove the oldest glyph from the font. 1361120fad34Smrg */ 1362120fad34Smrg if (font->newest != FT_UINT_MAX) { 1363120fad34Smrg XftGlyphUsage *xuse = (XftGlyphUsage *) font->glyphs[font->newest]; 1364120fad34Smrg if ((glyphindex = xuse->newer) != FT_UINT_MAX) 1365120fad34Smrg XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 1366120fad34Smrg } 1367120fad34Smrg } 1368120fad34Smrg else if (font->use_free_glyphs) 1369120fad34Smrg { 1370120fad34Smrg /* 1371120fad34Smrg * Pick a random glyph from the font and remove it from the cache 1372120fad34Smrg */ 13730e0b1094Smrg glyph_memory = ((unsigned long)rand() % font->glyph_memory); 1374120fad34Smrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 1375120fad34Smrg { 1376120fad34Smrg xftg = font->glyphs[glyphindex]; 1377120fad34Smrg if (xftg) 1378120fad34Smrg { 1379120fad34Smrg if (xftg->glyph_memory > glyph_memory) 1380120fad34Smrg { 1381120fad34Smrg XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 1382120fad34Smrg break; 1383120fad34Smrg } 1384120fad34Smrg glyph_memory -= xftg->glyph_memory; 1385120fad34Smrg } 1386120fad34Smrg } 1387c76ae52dSmrg } 1388c76ae52dSmrg else 1389c76ae52dSmrg { 1390120fad34Smrg /* 1391120fad34Smrg * Free all glyphs, since they are part of a set. 1392120fad34Smrg */ 1393c76ae52dSmrg if (font->glyphset) 1394c76ae52dSmrg { 1395c76ae52dSmrg XRenderFreeGlyphSet (dpy, font->glyphset); 1396c76ae52dSmrg font->glyphset = 0; 1397c76ae52dSmrg } 1398120fad34Smrg for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) 1399c76ae52dSmrg { 1400120fad34Smrg xftg = font->glyphs[glyphindex]; 1401120fad34Smrg if (xftg) 1402c76ae52dSmrg { 1403120fad34Smrg if (xftg->glyph_memory > 0) 1404120fad34Smrg { 1405120fad34Smrg XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); 1406120fad34Smrg } 1407c76ae52dSmrg } 1408c76ae52dSmrg } 1409c76ae52dSmrg } 1410120fad34Smrg 1411c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 1412c76ae52dSmrg _XftFontValidateMemory (dpy, pub); 1413c76ae52dSmrg} 1414c76ae52dSmrg 1415c76ae52dSmrg_X_HIDDEN void 1416c76ae52dSmrg_XftFontManageMemory (Display *dpy, XftFont *pub) 1417c76ae52dSmrg{ 1418c76ae52dSmrg XftFontInt *font = (XftFontInt *) pub; 1419c76ae52dSmrg 1420c76ae52dSmrg if (font->max_glyph_memory) 1421c76ae52dSmrg { 1422c76ae52dSmrg if (XftDebug() & XFT_DBG_CACHE) 1423c76ae52dSmrg { 1424c76ae52dSmrg if (font->glyph_memory > font->max_glyph_memory) 1425120fad34Smrg printf ("Reduce memory for font 0x%lx from %lu to %lu\n", 1426c76ae52dSmrg font->glyphset ? font->glyphset : (unsigned long) font, 1427c76ae52dSmrg font->glyph_memory, font->max_glyph_memory); 1428c76ae52dSmrg } 1429c76ae52dSmrg while (font->glyph_memory > font->max_glyph_memory) 1430c76ae52dSmrg _XftFontUncacheGlyph (dpy, pub); 1431c76ae52dSmrg } 1432c76ae52dSmrg _XftDisplayManageMemory (dpy); 1433c76ae52dSmrg} 1434