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);
 	}

Reply via email to