Module Name: xsrc Committed By: mrg Date: Fri Sep 9 23:18:56 UTC 2022
Modified Files: xsrc/external/mit/libXft/dist/src: xftdpy.c xftglyphs.c Log Message: merge libXft 2.3.5. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 xsrc/external/mit/libXft/dist/src/xftdpy.c cvs rdiff -u -r1.4 -r1.5 xsrc/external/mit/libXft/dist/src/xftglyphs.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: xsrc/external/mit/libXft/dist/src/xftdpy.c diff -u xsrc/external/mit/libXft/dist/src/xftdpy.c:1.5 xsrc/external/mit/libXft/dist/src/xftdpy.c:1.6 --- xsrc/external/mit/libXft/dist/src/xftdpy.c:1.5 Mon Aug 23 21:05:09 2021 +++ xsrc/external/mit/libXft/dist/src/xftdpy.c Fri Sep 9 23:18:56 2022 @@ -22,10 +22,12 @@ #include "xftint.h" +#define BtoS(b) ((b) ? "true" : "false") + _X_HIDDEN XftDisplayInfo *_XftDisplayInfo; static int -_XftCloseDisplay (Display *dpy, XExtCodes *codes) +_XftCloseDisplay (Display *dpy, XExtCodes *codes _X_UNUSED) { XftDisplayInfo *info, **prev; @@ -51,7 +53,8 @@ _XftCloseDisplay (Display *dpy, XExtCode for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next) if (info->display == dpy) break; - *prev = info->next; + if (info != NULL) + *prev = info->next; free (info); return 0; @@ -85,7 +88,7 @@ _XftDisplayInfoGet (Display *dpy, FcBool if (!createIfNecessary) return NULL; - info = (XftDisplayInfo *) malloc (sizeof (XftDisplayInfo)); + info = malloc (sizeof (XftDisplayInfo)); if (!info) goto bail0; info->codes = XAddExtension (dpy); @@ -169,7 +172,7 @@ _XftDisplayInfoGet (Display *dpy, FcBool XFT_MAX_GLYPH_MEMORY, 0, XFT_DPY_MAX_GLYPH_MEMORY); if (XftDebug () & XFT_DBG_CACHE) - printf ("global max cache memory %ld\n", info->max_glyph_memory); + printf ("global max cache memory %lu\n", info->max_glyph_memory); info->num_unref_fonts = 0; @@ -177,7 +180,14 @@ _XftDisplayInfoGet (Display *dpy, FcBool XFT_MAX_UNREF_FONTS, 0, XFT_DPY_MAX_UNREF_FONTS); if (XftDebug() & XFT_DBG_CACHE) - printf ("global max unref fonts %d\n", info->max_unref_fonts); + printf ("global max unref fonts %d\n", info->max_unref_fonts); + + info->track_mem_usage = FcFalse; + info->track_mem_usage = XftDefaultGetBool (dpy, + XFT_TRACK_MEM_USAGE, 0, + FcFalse); + if (XftDebug() & XFT_DBG_CACHE) + printf ("global track mem usage %s\n", BtoS(info->track_mem_usage)); memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH); return info; @@ -210,7 +220,7 @@ _XftDisplayValidateMemory (XftDisplayInf glyph_memory += font->glyph_memory; } if (glyph_memory != info->glyph_memory) - printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n", + printf ("Display glyph cache incorrect has %lu bytes, should have %lu\n", info->glyph_memory, glyph_memory); } @@ -227,7 +237,7 @@ _XftDisplayManageMemory (Display *dpy) if (XftDebug () & XFT_DBG_CACHE) { if (info->glyph_memory > info->max_glyph_memory) - printf ("Reduce global memory from %ld to %ld\n", + printf ("Reduce global memory from %lu to %lu\n", info->glyph_memory, info->max_glyph_memory); _XftDisplayValidateMemory (info); } @@ -272,16 +282,29 @@ XftDefaultSet (Display *dpy, FcPattern * if (info->defaults) FcPatternDestroy (info->defaults); info->defaults = defaults; + if (!info->max_glyph_memory) info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY; info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY, 0, (int)info->max_glyph_memory); + if (XftDebug () & XFT_DBG_CACHE) + printf ("update max cache memory %lu\n", info->max_glyph_memory); + if (!info->max_unref_fonts) info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS; info->max_unref_fonts = XftDefaultGetInteger (dpy, XFT_MAX_UNREF_FONTS, 0, info->max_unref_fonts); + if (XftDebug() & XFT_DBG_CACHE) + printf ("update max unref fonts %d\n", info->max_unref_fonts); + + info->track_mem_usage = XftDefaultGetBool (dpy, + XFT_TRACK_MEM_USAGE, 0, + info->track_mem_usage); + if (XftDebug() & XFT_DBG_CACHE) + printf ("update track mem usage %s\n", BtoS(info->track_mem_usage)); + return True; } Index: xsrc/external/mit/libXft/dist/src/xftglyphs.c diff -u xsrc/external/mit/libXft/dist/src/xftglyphs.c:1.4 xsrc/external/mit/libXft/dist/src/xftglyphs.c:1.5 --- xsrc/external/mit/libXft/dist/src/xftglyphs.c:1.4 Mon Aug 23 21:05:09 2021 +++ xsrc/external/mit/libXft/dist/src/xftglyphs.c Fri Sep 9 23:18:56 2022 @@ -1,23 +1,24 @@ /* + * Copyright © 2022 Thomas E. Dickey * Copyright © 2000 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the above copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The above copyright holders make no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "xftint.h" @@ -26,12 +27,54 @@ #include FT_SYNTHESIS_H +#include FT_GLYPH_H + +typedef double m3x3[3][3]; + +static void +m3x3_uniform(m3x3 m) +{ + m[0][0] = m[1][1] = m[2][2] = 1.0; + m[0][1] = m[1][0] = m[0][2] = m[1][2] = m[2][0] = m[2][1] = 0; +} + +static void +m3x3_transform(FT_Vector *v, m3x3 m) +{ + double x, y; + + x = (double)v->x; + y = (double)v->y; + v->x = (FT_Pos)(x * m[0][0] + y * m[0][1] + m[0][2] + 0.5); + v->y = (FT_Pos)(x * m[1][0] + y * m[1][1] + m[1][2] + 0.5); +} + +static void +m3x3_invert(m3x3 m, m3x3 mi) +{ + double det; + + det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]); + det -= m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]); + det += m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + det = 1.0 / det; + mi[0][0] = det * (m[1][1] * m[2][2] - m[1][2] * m[2][1]); + mi[1][0] = det * (m[1][2] * m[2][0] - m[1][0] * m[2][2]); + mi[2][0] = det * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); + mi[0][1] = det * (m[0][2] * m[2][1] - m[0][1] * m[2][2]); + mi[1][1] = det * (m[0][0] * m[2][2] - m[0][2] * m[2][0]); + mi[2][1] = det * (m[0][1] * m[2][0] - m[0][0] * m[2][1]); + mi[0][2] = det * (m[0][1] * m[1][2] - m[0][2] * m[1][1]); + mi[1][2] = det * (m[0][2] * m[1][0] - m[0][0] * m[1][2]); + mi[2][2] = det * (m[0][0] * m[1][1] - m[0][1] * m[1][0]); +} + /* * Validate the memory info for a font */ static void -_XftFontValidateMemory (Display *dpy, XftFont *public) +_XftFontValidateMemory (Display *dpy _X_UNUSED, XftFont *public) { XftFontInt *font = (XftFontInt *) public; unsigned long glyph_memory; @@ -48,10 +91,72 @@ _XftFontValidateMemory (Display *dpy, Xf } } if (glyph_memory != font->glyph_memory) - printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n", + printf ("Font glyph cache incorrect has %lu bytes, should have %lu\n", font->glyph_memory, glyph_memory); } +/* + * Validate the glyph usage-links for a font. + */ +static void +_XftValidateGlyphUsage(XftFontInt *font) +{ + if (font->newest != FT_UINT_MAX) { + FT_UInt forward; + FT_UInt reverse; + FT_UInt next; + XftGlyphUsage *x1st = (XftGlyphUsage *) font->glyphs[font->newest]; + XftGlyphUsage *xuse = x1st; + for (forward = 1, + next = x1st->newer; + xuse != NULL && + next != font->newest; + next = xuse->newer) { + if (next >= font->num_glyphs) { + printf("Xft: out of range; %d\n", next); + break; + } + if (++forward > font->total_inuse) { + printf("Xft: too many in-use glyphs (%d vs %d)\n", + forward, font->total_inuse); + if (forward > font->total_inuse + 10) + break; + } + xuse = (XftGlyphUsage *) font->glyphs[next]; + } + if (forward < font->total_inuse) { + printf("Xft: too few in-use glyphs (%u vs %d)\n", + forward, font->total_inuse); + } + for (reverse = 1, + next = x1st->older; + xuse != NULL && + next != font->newest; + next = xuse->older) { + if (next >= font->num_glyphs) { + printf("Xft out of range; %d\n", next); + break; + } + if (++reverse > font->total_inuse) { + printf("Xft: too many in-use glyphs (%d vs %d)\n", + reverse, font->total_inuse); + if (reverse > font->total_inuse + 10) + break; + } + xuse = (XftGlyphUsage *) font->glyphs[next]; + } + if (reverse < font->total_inuse) { + printf("Xft: too few in-use glyphs (%u vs %d)\n", + reverse, font->total_inuse); + } + if (forward != reverse) { + printf("Xft: forward %d vs reverse %d\n", + forward, reverse); + exit(1); + } + } +} + /* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot * into a different format. For example, we want to convert a * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit @@ -78,7 +183,9 @@ _XftFontValidateMemory (Display *dpy, Xf static int _compute_xrender_bitmap_size( FT_Bitmap* target, FT_GlyphSlot slot, - FT_Render_Mode mode ) + FT_Render_Mode mode, + FT_Matrix* matrix, + m3x3 m ) { FT_Bitmap* ftbit; int width, height, pitch; @@ -91,6 +198,63 @@ _compute_xrender_bitmap_size( FT_Bitmap* width = (int)ftbit->width; height = (int)ftbit->rows; + + if ( matrix && mode == FT_RENDER_MODE_NORMAL ) + { + FT_Matrix mirror, inverse; + FT_Vector vector; + int xc, yc; + int left, right, top, bottom; + + left = right = top = bottom = 0; + for (xc = 0; xc <= 1; xc++) { + for (yc = 0; yc <= 1; yc++) { + vector.x = xc * width; + vector.y = yc * height; + FT_Vector_Transform(&vector, matrix); + if (xc == 0 && yc == 0) { + left = right = (int)vector.x; + top = bottom = (int)vector.y; + } else { + if (left > vector.x) left = (int)vector.x; + if (right < vector.x) right = (int)vector.x; + if (bottom > vector.y) bottom = (int)vector.y; + if (top < vector.y) top = (int)vector.y; + } + } + } + width = (int)(right - left); + height = (int)(top - bottom); + + mirror.xx = + 0x10000; + mirror.yy = - 0x10000; + mirror.xy = mirror.yx = 0; + inverse = *matrix; + FT_Matrix_Multiply(&mirror, &inverse); + FT_Matrix_Invert(&inverse); + FT_Matrix_Multiply(&mirror, &inverse); + + vector.x = vector.y = 0; + FT_Vector_Transform(&vector, &inverse); + left = (int)vector.x; + bottom = (int)vector.y; + vector.x = width; + vector.y = height; + FT_Vector_Transform(&vector, &inverse); + right = (int)vector.x; + top = (int)vector.y; + left = (right - left) - (int)ftbit->width; + bottom = (top - bottom) - (int)ftbit->rows; + + m[0][0] = (double)inverse.xx / 0x10000; + m[0][1] = (double)inverse.xy / 0x10000; + m[1][0] = (double)inverse.yx / 0x10000; + m[1][1] = (double)inverse.yy / 0x10000; + m[0][2] = (double)-left / 2; + m[1][2] = (double)-bottom / 2; + m[2][0] = m[2][1] = 0.0; + m[2][2] = 1.0; + } pitch = (width+3) & ~3; switch ( ftbit->pixel_mode ) @@ -112,6 +276,10 @@ _compute_xrender_bitmap_size( FT_Bitmap* } break; + case FT_PIXEL_MODE_BGRA: + pitch = width * 4; + break; + case FT_PIXEL_MODE_LCD: if ( mode != FT_RENDER_MODE_LCD ) return -1; @@ -143,6 +311,125 @@ _compute_xrender_bitmap_size( FT_Bitmap* } /* this functions converts the glyph bitmap found in a FT_GlyphSlot + * into a different format while scaling by applying the given matrix + * (see _compute_xrender_bitmap_size) + * + * you should call this function after _compute_xrender_bitmap_size + * + * target :: target bitmap descriptor. Note that its 'buffer' pointer + * must point to memory allocated by the caller + * + * source :: the source bitmap descriptor + * + * matrix :: the scaling matrix to apply + */ +static void +_scaled_fill_xrender_bitmap( FT_Bitmap* target, + FT_Bitmap* source, + m3x3 m ) +{ + unsigned char* src_buf = source->buffer; + unsigned char* dst_line = target->buffer; + int src_pitch = source->pitch; + int width = (int) target->width; + int height = (int) target->rows; + int pitch = target->pitch; + int i, x, y; + FT_Vector vector, vector0; + int sampling_width; + int sampling_height; + int sample_count; + + if ( src_pitch < 0 ) + src_buf -= ((unsigned) src_pitch * (source->rows - 1)); + + /* compute how many source pixels a target pixel spans */ + vector.x = 1; + vector.y = 1; + m3x3_transform(&vector, m); + vector0.x = 0; + vector0.y = 0; + m3x3_transform(&vector0, m); + sampling_width = (int) ((vector.x - vector0.x) / 2); + sampling_height = (int) ((vector.y - vector0.y) / 2); + if (sampling_width < 0) sampling_width = -sampling_width; + if (sampling_height < 0) sampling_height = -sampling_height; + sample_count = (2 * sampling_width + 1) * (2 * sampling_height + 1); + + for ( y = height; y > 0; y--, dst_line += pitch ) + { + for ( x = 0; x < width; x++ ) + { + unsigned char* src; + + /* compute target pixel location in source space */ + vector.x = x; + vector.y = height - y; + m3x3_transform(&vector, m); + + if (source->pixel_mode == FT_PIXEL_MODE_BGRA) + { + if (vector.x < -sampling_width + || vector.x > (source->width + (unsigned) sampling_width)) + continue; + if (vector.y < -sampling_height + || vector.y > (source->rows + (unsigned) sampling_height)) + continue; + } + else + { + if (vector.x < 0 || vector.x >= source->width) + continue; + if (vector.y < 0 || vector.y >= source->rows) + continue; + } + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: /* convert mono to 8-bit gray, scale using nearest pixel */ + src = src_buf + (vector.y * src_pitch); + if ( src[(vector.x >> 3)] & (0x80 >> (vector.x & 7)) ) + dst_line[x] = 0xff; + break; + + case FT_PIXEL_MODE_GRAY: /* scale using nearest pixel */ + src = src_buf + (vector.y * src_pitch); + dst_line[x] = src[vector.x]; + break; + + case FT_PIXEL_MODE_BGRA: /* scale by averaging all relevant source pixels, keep BGRA format */ + { + int sample_x, sample_y; + int bgra[4] = { 0, 0, 0, 0 }; + + for (sample_y = - sampling_height; sample_y < sampling_height + 1; ++sample_y) + { + int src_y = (int) (vector.y + sample_y); + + if (src_y < 0 || (FT_Pos) src_y >= source->rows) + continue; + src = src_buf + (src_y * src_pitch); + for (sample_x = - sampling_width; sample_x < sampling_width + 1; ++sample_x) + { + int src_x = (int) (vector.x + sample_x); + + if (src_x < 0 || (FT_Pos) src_x >= source->width) + continue; + for (i = 0; i < 4; ++i) + bgra[i] += src[src_x * 4 + i]; + } + } + + for (i = 0; i < 4; ++i) + dst_line[4 * x + i] = (unsigned char) (bgra[i] / sample_count); + break; + } + } + } + } +} + +/* this functions converts the glyph bitmap found in a FT_GlyphSlot * into a different format (see _compute_xrender_bitmap_size) * * you should call this function after _compute_xrender_bitmap_size @@ -166,15 +453,15 @@ _fill_xrender_bitmap( FT_Bitmap* target, { unsigned char* srcLine = ftbit->buffer; - unsigned char* dstLine = target->buffer; - int src_pitch = ftbit->pitch; - int width = (int)target->width; - int height = (int)target->rows; - int pitch = target->pitch; - int subpixel; - int h; + unsigned char* dstLine = target->buffer; + int src_pitch = ftbit->pitch; + int width = (int)target->width; + int height = (int)target->rows; + int pitch = target->pitch; + int subpixel; + int h; - subpixel = ( mode == FT_RENDER_MODE_LCD || + subpixel = ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V ); if ( src_pitch < 0 ) @@ -244,6 +531,11 @@ _fill_xrender_bitmap( FT_Bitmap* target, } break; + case FT_PIXEL_MODE_BGRA: /* Preserve BGRA format */ + for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch ) + memcpy( dstLine, srcLine, (size_t) width * 4 ); + break; + case FT_PIXEL_MODE_LCD: if ( !bgr ) { @@ -363,8 +655,11 @@ XftFontLoadGlyphs (Display *dpy, FT_Bitmap* ftbit; FT_Bitmap local; FT_Vector vector; + m3x3 m; FT_Face face; FT_Render_Mode mode = FT_RENDER_MODE_MONO; + FcBool transform; + FcBool glyph_transform; if (!info) return; @@ -374,6 +669,8 @@ XftFontLoadGlyphs (Display *dpy, if (!face) return; + if (font->info.color) + mode = FT_RENDER_MODE_NORMAL; if (font->info.antialias) { switch (font->info.rgba) { @@ -390,6 +687,8 @@ XftFontLoadGlyphs (Display *dpy, } } + transform = font->info.transform && mode != FT_RENDER_MODE_MONO; + while (nglyph--) { glyphindex = *glyphs++; @@ -440,29 +739,29 @@ XftFontLoadGlyphs (Display *dpy, /* * Compute glyph metrics from FreeType information */ - if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP) + if (transform) { /* * calculate the true width by transforming all four corners. */ int xc, yc; left = right = top = bottom = 0; - for(xc = 0; xc <= 1; xc ++) { - for(yc = 0; yc <= 1; yc++) { + for (xc = 0; xc <= 1; xc++) { + for (yc = 0; yc <= 1; yc++) { vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width; vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height; FT_Vector_Transform(&vector, &font->info.matrix); if (XftDebug() & XFT_DBG_GLYPH) printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, (int) vector.x, (int) vector.y); - if(xc == 0 && yc == 0) { + if (xc == 0 && yc == 0) { left = right = (int)vector.x; top = bottom = (int)vector.y; } else { - if(left > vector.x) left = (int)vector.x; - if(right < vector.x) right = (int)vector.x; - if(bottom > vector.y) bottom = (int)vector.y; - if(top < vector.y) top = (int)vector.y; + if (left > vector.x) left = (int)vector.x; + if (right < vector.x) right = (int)vector.x; + if (bottom > vector.y) bottom = (int)vector.y; + if (top < vector.y) top = (int)vector.y; } } @@ -470,7 +769,7 @@ XftFontLoadGlyphs (Display *dpy, left = (int)FLOOR(left); right = (int)CEIL(right); bottom = (int)FLOOR(bottom); - top = CEIL(top); + top = (int)CEIL(top); } else { left = (int)FLOOR( glyphslot->metrics.horiBearingX ); @@ -480,14 +779,11 @@ XftFontLoadGlyphs (Display *dpy, bottom = (int)FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height ); } - width = TRUNC(right - left); - height = TRUNC( top - bottom ); - /* * Clip charcell glyphs to the bounding box * XXX transformed? */ - if (font->info.spacing >= FC_CHARCELL && !font->info.transform) + if (font->info.spacing >= FC_CHARCELL && !transform) { if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) { @@ -500,7 +796,6 @@ XftFontLoadGlyphs (Display *dpy, adjust = top; top -= adjust; bottom -= adjust; - height = font->public.max_advance_width; } } else @@ -514,23 +809,24 @@ XftFontLoadGlyphs (Display *dpy, adjust = left; left -= adjust; right -= adjust; - width = font->public.max_advance_width; } } } + glyph_transform = transform; if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP ) { error = FT_Render_Glyph( face->glyph, mode ); if (error) continue; + glyph_transform = False; } FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE ); if (font->info.spacing >= FC_MONO) { - if (font->info.transform) + if (transform) { if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT) { @@ -542,9 +838,9 @@ XftFontLoadGlyphs (Display *dpy, vector.x = face->size->metrics.max_advance; vector.y = 0; } - FT_Vector_Transform (&vector, &font->info.matrix); - xftg->metrics.xOff = (short)(vector.x >> 6); - xftg->metrics.yOff = (short)(-(vector.y >> 6)); + FT_Vector_Transform(&vector, &font->info.matrix); + xftg->metrics.xOff = (short)(TRUNC(ROUND(vector.x))); + xftg->metrics.yOff = (short)(TRUNC(ROUND(vector.y))); } else { @@ -603,7 +899,7 @@ XftFontLoadGlyphs (Display *dpy, { for (x = 0; x < width * 8; x++) { - printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' '); + printf ("%c", (line[x>>3] & (1 << (x & 7))) ? '#' : ' '); } } printf ("|\n"); @@ -613,20 +909,35 @@ XftFontLoadGlyphs (Display *dpy, } } - size = _compute_xrender_bitmap_size( &local, glyphslot, mode ); + m3x3_uniform(m); + size = _compute_xrender_bitmap_size( &local, glyphslot, mode, glyph_transform ? &font->info.matrix : NULL, m ); if ( size < 0 ) continue; xftg->metrics.width = (unsigned short)local.width; xftg->metrics.height = (unsigned short)local.rows; - xftg->metrics.x = (short)(- glyphslot->bitmap_left); - xftg->metrics.y = (short)( glyphslot->bitmap_top); + if (glyph_transform) + { + m3x3 mi; + + m3x3_invert(m, mi); + vector.x = - glyphslot->bitmap_left; + vector.y = glyphslot->bitmap_top; + m3x3_transform(&vector, mi); + xftg->metrics.x = (short)vector.x; + xftg->metrics.y = (short)vector.y; + } + else + { + xftg->metrics.x = (short)(- glyphslot->bitmap_left); + xftg->metrics.y = (short)( glyphslot->bitmap_top); + } /* * If the glyph is relatively large (> 1% of server memory), * don't send it until necessary. */ - if (!need_bitmaps && size > info->max_glyph_memory / 100) + if (!need_bitmaps && ((unsigned long) size > (info->max_glyph_memory / 100))) continue; /* @@ -645,9 +956,12 @@ XftFontLoadGlyphs (Display *dpy, local.buffer = bufBitmap; - _fill_xrender_bitmap( &local, glyphslot, mode, - (font->info.rgba == FC_RGBA_BGR || - font->info.rgba == FC_RGBA_VBGR ) ); + if (mode == FT_RENDER_MODE_NORMAL && glyph_transform) + _scaled_fill_xrender_bitmap(&local, &glyphslot->bitmap, m); + else + _fill_xrender_bitmap( &local, glyphslot, mode, + (font->info.rgba == FC_RGBA_BGR || + font->info.rgba == FC_RGBA_VBGR) ); /* * Copy or convert into local buffer. @@ -662,7 +976,12 @@ XftFontLoadGlyphs (Display *dpy, */ glyph = (Glyph) glyphindex; - xftg->glyph_memory = (size_t)size + sizeof (XftGlyph); + if (xftg->picture) + { + XRenderFreePicture(dpy, xftg->picture); + xftg->picture = 0; + } + xftg->glyph_memory = (size_t)size + font->sizeof_glyph; if (font->format) { if (!font->glyphset) @@ -685,15 +1004,43 @@ XftFontLoadGlyphs (Display *dpy, } } } - else if ( mode != FT_RENDER_MODE_NORMAL ) + else if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA || mode != FT_RENDER_MODE_NORMAL) { /* invert ARGB <=> BGRA */ if (ImageByteOrder (dpy) != XftNativeByteOrder ()) XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2); } - XRenderAddGlyphs (dpy, font->glyphset, &glyph, - &xftg->metrics, 1, - (char *) bufBitmap, size); + + if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + Pixmap pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), local.width, local.rows, 32); + GC gc = XCreateGC(dpy, pixmap, 0, NULL); + XImage image = { + (int) local.width, (int) local.rows, 0, ZPixmap, (char *)bufBitmap, + dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32, + 32, (int) (local.width * 4 - (unsigned) local.pitch), 32, + 0, 0, 0, NULL, { NULL } + }; + + XInitImage(&image); + XPutImage(dpy, pixmap, gc, &image, 0, 0, 0, 0, local.width, local.rows); + xftg->picture = XRenderCreatePicture(dpy, pixmap, font->format, 0, NULL); + + XFreeGC(dpy, gc); + XFreePixmap(dpy, pixmap); + /* + * Record 256 times higher memory pressure for unrotated + * pictures, and maximum for rotated pictures. + */ + if (font->info.matrix.xy || font->info.matrix.yx) + xftg->glyph_memory += font->max_glyph_memory - (unsigned long) size; + else + xftg->glyph_memory += (size_t)size * 255; + } + else + XRenderAddGlyphs (dpy, font->glyphset, &glyph, + &xftg->metrics, 1, + (char *) bufBitmap, size); } else { @@ -712,8 +1059,46 @@ XftFontLoadGlyphs (Display *dpy, if (XftDebug() & XFT_DBG_CACHE) _XftFontValidateMemory (dpy, pub); if (XftDebug() & XFT_DBG_CACHEV) - printf ("Caching glyph 0x%x size %ld\n", glyphindex, + printf ("Caching glyph 0x%x size %lu\n", glyphindex, xftg->glyph_memory); + + if (font->track_mem_usage) { + XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; + + if (font->newest == FT_UINT_MAX) { + xuse->older = glyphindex; + xuse->newer = glyphindex; + if (XftDebug() & XFT_DBG_USAGE) + printf("alloc %p -> %d: %p USE %d.%d\n", + (void *) font, glyphindex, + (void *) xuse, xuse->older, xuse->newer); + } else { + XftGlyphUsage *xnew; + XftGlyphUsage *xold; + + assert(font->glyphs[font->newest] != NULL); + xnew = (XftGlyphUsage *) font->glyphs[font->newest]; + + assert(font->glyphs[xnew->newer] != NULL); + xold = (XftGlyphUsage *) font->glyphs[xnew->newer]; + + xuse->older = font->newest; + xuse->newer = xnew->newer; + xnew->newer = glyphindex; + xold->older = glyphindex; + if (XftDebug() & XFT_DBG_USAGE) + printf("alloc %p -> %d: %p USE %d.%d, %p NEW %d.%d %p OLD %d.%d\n", + (void *) font, glyphindex, + (void *) xuse, xuse->older, xuse->newer, + (void *) xnew, xnew->older, xnew->newer, + (void *) xold, xold->older, xold->newer); + } + + font->newest = glyphindex; + font->total_inuse++; + if (XftDebug() & XFT_DBG_USAGE) + _XftValidateGlyphUsage(font); + } } if (bufBitmap != bufLocal) free (bufBitmap); @@ -742,9 +1127,14 @@ XftFontUnloadGlyphs (Display *dpy, continue; if (xftg->glyph_memory) { + if (XftDebug() & XFT_DBG_CACHEV) + printf ("Uncaching glyph 0x%x size %lu\n", + glyphindex, xftg->glyph_memory); if (font->format) { - if (font->glyphset) + if (xftg->picture) + XRenderFreePicture(dpy, xftg->picture); + else if (font->glyphset) { glyphBuf[nused++] = (Glyph) glyphindex; if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0])) @@ -754,17 +1144,52 @@ XftFontUnloadGlyphs (Display *dpy, } } } - else - { - if (xftg->bitmap) - free (xftg->bitmap); - } + else if (xftg->bitmap) + free (xftg->bitmap); font->glyph_memory -= xftg->glyph_memory; if (info) info->glyph_memory -= xftg->glyph_memory; } + + if (font->track_mem_usage) { + XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; + XftGlyphUsage *xtmp; + + if (XftDebug() & XFT_DBG_USAGE) + printf("free %p -> %p USE %d.%d\n", + (void *) font, (void *) xuse, xuse->older, xuse->newer); + + if (xuse->older != FT_UINT_MAX) { + xtmp = (XftGlyphUsage *) font->glyphs[xuse->older]; + if (xtmp != NULL) { + /* update link around to oldest glyph */ + xtmp->newer = xuse->newer; + } + if (font->newest == glyphindex) { + if (font->newest == xuse->older) + font->newest = FT_UINT_MAX; + else + font->newest = xuse->older; + } + } + if (xuse->newer != FT_UINT_MAX) { + xtmp = (XftGlyphUsage *) font->glyphs[xuse->newer]; + if (xtmp != NULL) { + /* update link around to newest glyph */ + xtmp->older = xuse->older; + } + } + if (font->total_inuse) { + font->total_inuse--; + } else { + fprintf (stderr, "Xft: glyph count error\n"); + } + if (XftDebug() & XFT_DBG_USAGE) + _XftValidateGlyphUsage(font); + } + free (xftg); - XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph)); + XftMemFree (XFT_MEM_GLYPH, font->sizeof_glyph); font->glyphs[glyphindex] = NULL; } if (font->glyphset && nused) @@ -790,13 +1215,21 @@ XftFontCheckGlyph (Display *dpy, { if (!xftg) { - xftg = (XftGlyph *) malloc (sizeof (XftGlyph)); + xftg = malloc (font->sizeof_glyph); if (!xftg) return FcFalse; - XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph)); + XftMemAlloc (XFT_MEM_GLYPH, font->sizeof_glyph); + xftg->bitmap = NULL; xftg->glyph_memory = 0; + xftg->picture = 0; font->glyphs[glyph] = xftg; + + if (font->track_mem_usage) { + XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; + xuse->older = FT_UINT_MAX; + xuse->newer = FT_UINT_MAX; + } } n = *nmissing; missing[n++] = glyph; @@ -808,14 +1241,46 @@ XftFontCheckGlyph (Display *dpy, *nmissing = n; return FcTrue; } - else - return FcFalse; + + /* + * Make unloading faster by moving newly-referenced glyphs to the front + * of the list, leaving the less-used glyphs on the end. + */ + if (font->track_mem_usage + && font->total_inuse > 10 + && font->newest != FT_UINT_MAX + && font->newest != glyph) + { + XftGlyphUsage *xuse = (XftGlyphUsage *) xftg; + XftGlyphUsage *xtmp = (XftGlyphUsage *) font->glyphs[font->newest]; + XftGlyphUsage *xold; + XftGlyphUsage *xnew; + + /* delink */ + xold = (XftGlyphUsage *) font->glyphs[xuse->older]; + xnew = (XftGlyphUsage *) font->glyphs[xuse->newer]; + assert(xold != NULL); + assert(xnew != NULL); + xold->newer = xuse->newer; + xnew->older = xuse->older; + + /* relink */ + xnew = (XftGlyphUsage *) font->glyphs[xtmp->newer]; + assert(xnew != NULL); + xnew->older = glyph; + xuse->older = font->newest; + xuse->newer = xtmp->newer; + xtmp->newer = glyph; + + font->newest = glyph; + } + return FcFalse; } _X_EXPORT FcBool -XftCharExists (Display *dpy, +XftCharExists (Display *dpy _X_UNUSED, XftFont *pub, - FcChar32 ucs4) + FcChar32 ucs4) { if (pub->charset) return FcCharSetHasChar (pub->charset, ucs4); @@ -859,14 +1324,14 @@ XftCharIndex (Display *dpy, offset = 1; } ent = ent + offset; - if (ent >= font->hash_value) + if (ent >= (FcChar32)font->hash_value) ent -= (FcChar32)font->hash_value; } return font->hash_table[ent].glyph; } /* - * Pick a random glyph from the font and remove it from the cache + * Remove glyph(s) from the font to reduce memory-usage. */ _X_HIDDEN void _XftFontUncacheGlyph (Display *dpy, XftFont *pub) @@ -878,40 +1343,64 @@ _XftFontUncacheGlyph (Display *dpy, XftF if (!font->glyph_memory) return; - if (font->use_free_glyphs) + + if (XftDebug() & XFT_DBG_CACHE) + _XftFontValidateMemory (dpy, pub); + + if (font->track_mem_usage) { + /* + * Remove the oldest glyph from the font. + */ + if (font->newest != FT_UINT_MAX) { + XftGlyphUsage *xuse = (XftGlyphUsage *) font->glyphs[font->newest]; + if ((glyphindex = xuse->newer) != FT_UINT_MAX) + XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); + } + } + else if (font->use_free_glyphs) + { + /* + * Pick a random glyph from the font and remove it from the cache + */ glyph_memory = ((unsigned long)rand() % font->glyph_memory); + for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) + { + xftg = font->glyphs[glyphindex]; + if (xftg) + { + if (xftg->glyph_memory > glyph_memory) + { + XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); + break; + } + glyph_memory -= xftg->glyph_memory; + } + } } else { + /* + * Free all glyphs, since they are part of a set. + */ if (font->glyphset) { XRenderFreeGlyphSet (dpy, font->glyphset); font->glyphset = 0; } - glyph_memory = 0; - } - - if (XftDebug() & XFT_DBG_CACHE) - _XftFontValidateMemory (dpy, pub); - for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) - { - xftg = font->glyphs[glyphindex]; - if (xftg) + for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++) { - if (xftg->glyph_memory > glyph_memory) + xftg = font->glyphs[glyphindex]; + if (xftg) { - if (XftDebug() & XFT_DBG_CACHEV) - printf ("Uncaching glyph 0x%x size %ld\n", - glyphindex, xftg->glyph_memory); - XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); - if (!font->use_free_glyphs) - continue; - break; + if (xftg->glyph_memory > 0) + { + XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1); + } } - glyph_memory -= xftg->glyph_memory; } } + if (XftDebug() & XFT_DBG_CACHE) _XftFontValidateMemory (dpy, pub); } @@ -926,7 +1415,7 @@ _XftFontManageMemory (Display *dpy, XftF if (XftDebug() & XFT_DBG_CACHE) { if (font->glyph_memory > font->max_glyph_memory) - printf ("Reduce memory for font 0x%lx from %ld to %ld\n", + printf ("Reduce memory for font 0x%lx from %lu to %lu\n", font->glyphset ? font->glyphset : (unsigned long) font, font->glyph_memory, font->max_glyph_memory); }