From b286302019c57dcf4ccabb05886ad5c02f2f4171 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 12 Aug 2021 14:17:53 +0200 Subject: [PATCH 1/2] libXft: update to 2.3.4 --- srcpkgs/libXft/template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srcpkgs/libXft/template b/srcpkgs/libXft/template index dd6263d3a420..1e86cd68fdc3 100644 --- a/srcpkgs/libXft/template +++ b/srcpkgs/libXft/template @@ -1,6 +1,6 @@ # Template file for 'libXft' pkgname=libXft -version=2.3.3 +version=2.3.4 revision=1 build_style=gnu-configure hostmakedepends="pkg-config" @@ -10,7 +10,7 @@ maintainer="Orphaned " license="MIT" homepage="$XORG_SITE" distfiles="${XORG_SITE}/lib/${pkgname}-${version}.tar.bz2" -checksum=225c68e616dd29dbb27809e45e9eadf18e4d74c50be43020ef20015274529216 +checksum=57dedaab20914002146bdae0cb0c769ba3f75214c4c91bd2613d6ef79fc9abdd post_install() { vlicense COPYING From 9eddae8e7f5c7029b11ef2ebc4d8f2d785cb0fd1 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Thu, 12 Aug 2021 14:18:15 +0200 Subject: [PATCH 2/2] libXft: fix colored emoji bug Include the patches from https://gitlab.freedesktop.org/xorg/lib/libxft/-/merge_requests/1 --- ...-_XftCompositeString-helper-function.patch | 94 +++ ...-a-_XftCompositeText-helper-function.patch | 123 ++++ ...-for-BGRA-glyphs-display-and-scaling.patch | 642 ++++++++++++++++++ 3 files changed, 859 insertions(+) create mode 100644 srcpkgs/libXft/patches/0001-Introduce-a-_XftCompositeString-helper-function.patch create mode 100644 srcpkgs/libXft/patches/0002-Introduce-a-_XftCompositeText-helper-function.patch create mode 100644 srcpkgs/libXft/patches/0003-Add-support-for-BGRA-glyphs-display-and-scaling.patch diff --git a/srcpkgs/libXft/patches/0001-Introduce-a-_XftCompositeString-helper-function.patch b/srcpkgs/libXft/patches/0001-Introduce-a-_XftCompositeString-helper-function.patch new file mode 100644 index 000000000000..3ba3d72590b0 --- /dev/null +++ b/srcpkgs/libXft/patches/0001-Introduce-a-_XftCompositeString-helper-function.patch @@ -0,0 +1,94 @@ +From 723092ece088559f1af299236305911f4ee4d450 Mon Sep 17 00:00:00 2001 +From: Maxime Coste +Date: Thu, 28 Jan 2021 19:59:10 +1100 +Subject: [PATCH 1/3] Introduce a _XftCompositeString helper function + +Dispatch to XRenderCompositeString{8,16,32} based off the given width. + +Signed-off-by: Maxime Coste +--- + src/xftrender.c | 61 ++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 43 insertions(+), 18 deletions(-) + +diff --git a/src/xftrender.c b/src/xftrender.c +index a352737..181c27a 100644 +--- a/src/xftrender.c ++++ b/src/xftrender.c +@@ -25,6 +25,47 @@ + #define NUM_LOCAL 1024 + #define NUM_ELT_LOCAL 128 + ++/* ++ * Dispatch glyph drawing to the correct XRenderCompositeString function ++ */ ++static void ++_XftCompositeString (Display *dpy, ++ int op, ++ Picture src, ++ Picture dst, ++ XRenderPictFormat *format, ++ GlyphSet glyphset, ++ int srcx, ++ int srcy, ++ int dstx, ++ int dsty, ++ int charwidth, ++ unsigned int *chars, ++ int nchars) ++{ ++ if (nchars == 0) ++ return; ++ ++ switch (charwidth) { ++ case 1: ++ default: ++ XRenderCompositeString8 (dpy, op, ++ src, dst, format, glyphset, ++ srcx, srcy, dstx, dsty, (char*)chars, nchars); ++ break; ++ case 2: ++ XRenderCompositeString16(dpy, op, ++ src, dst, format, glyphset, ++ srcx, srcy, dstx, dsty, (unsigned short*)chars, nchars); ++ break; ++ case 4: ++ XRenderCompositeString32(dpy, op, ++ src, dst, format, glyphset, ++ srcx, srcy, dstx, dsty, (unsigned int*)chars, nchars); ++ break; ++ } ++} ++ + /* + * Use the Render extension to draw the glyphs + */ +@@ -114,24 +155,8 @@ XftGlyphRender (Display *dpy, + case 4: char32[i] = (unsigned int) wire; break; + } + } +- switch (width) { +- case 1: +- default: +- XRenderCompositeString8 (dpy, op, +- src, dst, font->format, font->glyphset, +- srcx, srcy, x, y, char8, nglyphs); +- break; +- case 2: +- XRenderCompositeString16(dpy, op, +- src, dst, font->format, font->glyphset, +- srcx, srcy, x, y, char16, nglyphs); +- break; +- case 4: +- XRenderCompositeString32(dpy, op, +- src, dst, font->format, font->glyphset, +- srcx, srcy, x, y, char32, nglyphs); +- break; +- } ++ _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset, ++ srcx, srcy, x, y, width, chars, nglyphs); + if (chars != char_local) + free (chars); + bail1: +-- +2.32.0 + diff --git a/srcpkgs/libXft/patches/0002-Introduce-a-_XftCompositeText-helper-function.patch b/srcpkgs/libXft/patches/0002-Introduce-a-_XftCompositeText-helper-function.patch new file mode 100644 index 000000000000..2112c39e4d8a --- /dev/null +++ b/srcpkgs/libXft/patches/0002-Introduce-a-_XftCompositeText-helper-function.patch @@ -0,0 +1,123 @@ +From e0fc4ce7e87ab9c4b47e5c8e693f070dfd0d2f7b Mon Sep 17 00:00:00 2001 +From: Maxime Coste +Date: Thu, 28 Jan 2021 20:05:13 +1100 +Subject: [PATCH 2/3] Introduce a _XftCompositeText helper function + +Dispatch to XRenderCompositeText{8,16,32} based off the given width. + +Signed-off-by: Maxime Coste +--- + src/xftrender.c | 83 +++++++++++++++++++++++++++++-------------------- + 1 file changed, 49 insertions(+), 34 deletions(-) + +diff --git a/src/xftrender.c b/src/xftrender.c +index 181c27a..5852b2e 100644 +--- a/src/xftrender.c ++++ b/src/xftrender.c +@@ -164,6 +164,49 @@ bail1: + _XftFontManageMemory (dpy, pub); + } + ++/* ++ * Dispatch glyph drawing to the correct XRenderCompositeText function ++ */ ++static void ++_XftCompositeText (Display *dpy, ++ int op, ++ Picture src, ++ Picture dst, ++ XRenderPictFormat *format, ++ int srcx, ++ int srcy, ++ int dstx, ++ int dsty, ++ int eltwidth, ++ XGlyphElt8 *elts, ++ int nelt) ++{ ++ if (nelt == 0) ++ return; ++ ++ switch (eltwidth) { ++ case 1: ++ default: ++ XRenderCompositeText8 (dpy, op, ++ src, dst, format, ++ srcx, srcy, dstx, dsty, ++ (XGlyphElt8*)elts, nelt); ++ break; ++ case 2: ++ XRenderCompositeText16(dpy, op, ++ src, dst, format, ++ srcx, srcy, dstx, dsty, ++ (XGlyphElt16*)elts, nelt); ++ break; ++ case 4: ++ XRenderCompositeText32(dpy, op, ++ src, dst, format, ++ srcx, srcy, dstx, dsty, ++ (XGlyphElt32*)elts, nelt); ++ break; ++ } ++} ++ + _X_EXPORT void + XftGlyphSpecRender (Display *dpy, + int op, +@@ -345,23 +388,9 @@ XftGlyphSpecRender (Display *dpy, + elts[nelt].nchars = n; + nelt++; + } +- switch (width) { +- case 1: +- XRenderCompositeText8 (dpy, op, src, dst, font->format, +- srcx, srcy, glyphs[0].x, glyphs[0].y, +- elts, nelt); +- break; +- case 2: +- XRenderCompositeText16 (dpy, op, src, dst, font->format, +- srcx, srcy, glyphs[0].x, glyphs[0].y, +- (XGlyphElt16 *) elts, nelt); +- break; +- case 4: +- XRenderCompositeText32 (dpy, op, src, dst, font->format, +- srcx, srcy, glyphs[0].x, glyphs[0].y, +- (XGlyphElt32 *) elts, nelt); +- break; +- } ++ _XftCompositeText(dpy, op, src, dst, font->format, ++ srcx, srcy, glyphs[0].x, glyphs[0].y, ++ width, elts, nelt); + + if (elts != elts_local) + free (elts); +@@ -635,23 +664,9 @@ XftGlyphFontSpecRender (Display *dpy, + elts[nelt].nchars = n; + nelt++; + } +- switch (width) { +- case 1: +- XRenderCompositeText8 (dpy, op, src, dst, format, +- srcx, srcy, glyphs[0].x, glyphs[0].y, +- elts, nelt); +- break; +- case 2: +- XRenderCompositeText16 (dpy, op, src, dst, format, +- srcx, srcy, glyphs[0].x, glyphs[0].y, +- (XGlyphElt16 *) elts, nelt); +- break; +- case 4: +- XRenderCompositeText32 (dpy, op, src, dst, format, +- srcx, srcy, glyphs[0].x, glyphs[0].y, +- (XGlyphElt32 *) elts, nelt); +- break; +- } ++ _XftCompositeText(dpy, op, src, dst, format, ++ srcx, srcy, glyphs[0].x, glyphs[0].y, ++ width, elts, nelt); + + if (elts != elts_local) + free (elts); +-- +2.32.0 + diff --git a/srcpkgs/libXft/patches/0003-Add-support-for-BGRA-glyphs-display-and-scaling.patch b/srcpkgs/libXft/patches/0003-Add-support-for-BGRA-glyphs-display-and-scaling.patch new file mode 100644 index 000000000000..73a7842b6348 --- /dev/null +++ b/srcpkgs/libXft/patches/0003-Add-support-for-BGRA-glyphs-display-and-scaling.patch @@ -0,0 +1,642 @@ +From d385aa3e5320d18918413df0e8aef3a713a47e0b Mon Sep 17 00:00:00 2001 +From: Maxime Coste +Date: Tue, 22 Oct 2019 22:46:49 +1100 +Subject: [PATCH 3/3] Add support for BGRA glyphs display and scaling + +Display is done using an XRender Picture, as XRender +glyphs are incompatible with BGRA rendering due to +their use of the glyph bitmap as a mask. + +Scaling is done by averaging all relevant pixel, which gives +much better result than nearest pixel sampling while staying +simple enough and not too computationally expensive. + +This enables color emoji rendering support. + +Fixes: #6 + +Signed-off-by: Maxime Coste +--- + src/xftfreetype.c | 18 +++- + src/xftglyphs.c | 234 +++++++++++++++++++++++++++++++++++++++++++--- + src/xftint.h | 2 + + src/xftrender.c | 69 +++++++++++--- + 4 files changed, 293 insertions(+), 30 deletions(-) + +diff --git a/src/xftfreetype.c b/src/xftfreetype.c +index 1f79a81..4325d65 100644 +--- a/src/xftfreetype.c ++++ b/src/xftfreetype.c +@@ -523,7 +523,7 @@ XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi) + /* + * Compute glyph load flags + */ +- fi->load_flags = FT_LOAD_DEFAULT; ++ fi->load_flags = FT_LOAD_DEFAULT | FT_LOAD_COLOR; + + #ifndef XFT_EMBEDDED_BITMAP + #define XFT_EMBEDDED_BITMAP "embeddedbitmap" +@@ -775,6 +775,7 @@ XftFontOpenInfo (Display *dpy, + FcChar32 hash_value; + FcChar32 rehash_value; + FcBool antialias; ++ FcBool color; + int max_glyph_memory; + int alloc_size; + int ascent, descent, height; +@@ -831,12 +832,18 @@ XftFontOpenInfo (Display *dpy, + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) + antialias = FcFalse; + ++ color = FT_HAS_COLOR(face) ? FcTrue : FcFalse; ++ + /* + * Find the appropriate picture format + */ + if (fi->render) + { +- if (antialias) ++ if (color) ++ { ++ format = XRenderFindStandardFormat (dpy, PictStandardARGB32); ++ } ++ else if (antialias) + { + switch (fi->rgba) { + case FC_RGBA_RGB: +@@ -968,6 +975,13 @@ XftFontOpenInfo (Display *dpy, + * which doesn't happen in XftFontInfoFill + */ + font->info.antialias = antialias; ++ ++ /* ++ * Set color value, which is only known once the ++ * font was loaded ++ */ ++ font->info.color = color; ++ + /* + * bump XftFile reference count + */ +diff --git a/src/xftglyphs.c b/src/xftglyphs.c +index b536df4..e0bad10 100644 +--- a/src/xftglyphs.c ++++ b/src/xftglyphs.c +@@ -26,6 +26,8 @@ + + #include FT_SYNTHESIS_H + ++#include FT_GLYPH_H ++ + /* + * Validate the memory info for a font + */ +@@ -78,9 +80,11 @@ _XftFontValidateMemory (Display *dpy, XftFont *public) + static int + _compute_xrender_bitmap_size( FT_Bitmap* target, + FT_GlyphSlot slot, +- FT_Render_Mode mode ) ++ FT_Render_Mode mode, ++ FT_Matrix* matrix ) + { + FT_Bitmap* ftbit; ++ FT_Vector vector; + int width, height, pitch; + + if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) +@@ -91,6 +95,16 @@ _compute_xrender_bitmap_size( FT_Bitmap* target, + + width = (int)ftbit->width; + height = (int)ftbit->rows; ++ ++ if ( matrix && mode == FT_RENDER_MODE_NORMAL ) ++ { ++ vector.x = ftbit->width; ++ vector.y = ftbit->rows; ++ FT_Vector_Transform(&vector, matrix); ++ ++ width = (int)vector.x; ++ height = (int)vector.y; ++ } + pitch = (width+3) & ~3; + + switch ( ftbit->pixel_mode ) +@@ -112,6 +126,10 @@ _compute_xrender_bitmap_size( FT_Bitmap* target, + } + break; + ++ case FT_PIXEL_MODE_BGRA: ++ pitch = width * 4; ++ break; ++ + case FT_PIXEL_MODE_LCD: + if ( mode != FT_RENDER_MODE_LCD ) + return -1; +@@ -142,6 +160,105 @@ _compute_xrender_bitmap_size( FT_Bitmap* target, + return pitch * height; + } + ++/* 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, ++ const FT_Matrix* matrix ) ++{ ++ unsigned char* src_buf = source->buffer; ++ unsigned char* dst_line = target->buffer; ++ int src_pitch = source->pitch; ++ int width = target->width; ++ int height = target->rows; ++ int pitch = target->pitch; ++ int h; ++ FT_Vector vector; ++ FT_Matrix inverse = *matrix; ++ int sampling_width; ++ int sampling_height; ++ int sample_count; ++ ++ if ( src_pitch < 0 ) ++ src_buf -= src_pitch * (source->rows - 1); ++ ++ FT_Matrix_Invert(&inverse); ++ ++ /* compute how many source pixels a target pixel spans */ ++ vector.x = 1; ++ vector.y = 1; ++ FT_Vector_Transform(&vector, &inverse); ++ sampling_width = vector.x / 2; ++ sampling_height = vector.y / 2; ++ sample_count = (2 * sampling_width + 1) * (2 * sampling_height + 1); ++ ++ for ( h = height; h > 0; h--, dst_line += pitch ) ++ { ++ int x; ++ ++ for ( x = 0; x < width; x++ ) ++ { ++ unsigned char* src; ++ ++#define CLAMP(x, min, max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) ++ ++ /* compute target pixel location in source space */ ++ vector.x = (x * 0x10000) + 0x10000 / 2; ++ vector.y = ((height - h) * 0x10000) + 0x10000 / 2; ++ FT_Vector_Transform(&vector, &inverse); ++ vector.x = CLAMP(FT_RoundFix(vector.x) / 0x10000, 0, source->width - 1); ++ vector.y = CLAMP(FT_RoundFix(vector.y) / 0x10000, 0, source->rows - 1); ++ ++ 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] = {}; ++ for (sample_y = - sampling_height; sample_y < sampling_height + 1; ++sample_y) ++ { ++ int src_y = CLAMP(vector.y + sample_y, 0, source->rows - 1); ++ src = src_buf + (src_y * src_pitch); ++ for (sample_x = - sampling_width; sample_x < sampling_width + 1; ++sample_x) ++ { ++ int src_x = CLAMP(vector.x + sample_x, 0, source->width - 1); ++ for (int i = 0; i < 4; ++i) ++ bgra[i] += src[src_x * 4 + i]; ++ } ++ } ++ ++ for (int i = 0; i < 4; ++i) ++ dst_line[4 * x + i] = 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) + * +@@ -244,6 +361,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, width * 4 ); ++ break; ++ + case FT_PIXEL_MODE_LCD: + if ( !bgr ) + { +@@ -339,6 +461,55 @@ _fill_xrender_bitmap( FT_Bitmap* target, + } + } + ++/* This function creates a Picture for the given glyph on the default root window ++ * It will only work in Xinerama mode ++ * ++ * dpy :: target display ++ * ++ * format :: target pixmap format ++ * ++ * width :: picture width ++ * ++ * width :: picture height ++ * ++ * data :: bitmap data ++ * ++ */ ++static Picture ++_create_glyph_bgra_picture (Display *dpy, ++ XRenderPictFormat *format, ++ int width, ++ int height, ++ unsigned char *data) ++{ ++ XImage image = { ++ width, height, 0, ZPixmap, (char *)data, ++ dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32, ++ 32, 0, 32, ++ 0, 0, 0 ++ }; ++ Picture picture; ++ Pixmap pixmap; ++ GC gc; ++ ++ pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height, 32); ++ if (!pixmap) ++ return None; ++ ++ gc = XCreateGC(dpy, pixmap, 0, NULL); ++ if (!gc) ++ return None; ++ ++ XInitImage(&image); ++ XPutImage(dpy, pixmap, gc, &image, 0, 0, 0, 0, width, height); ++ picture = XRenderCreatePicture(dpy, pixmap, format, 0, NULL); ++ ++ XFreeGC(dpy, gc); ++ XFreePixmap(dpy, pixmap); ++ ++ return picture; ++} ++ + _X_EXPORT void + XftFontLoadGlyphs (Display *dpy, + XftFont *pub, +@@ -365,6 +536,8 @@ XftFontLoadGlyphs (Display *dpy, + FT_Vector vector; + FT_Face face; + FT_Render_Mode mode = FT_RENDER_MODE_MONO; ++ FcBool transform; ++ FcBool glyph_transform; + + if (!info) + return; +@@ -374,6 +547,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 +565,8 @@ XftFontLoadGlyphs (Display *dpy, + } + } + ++ transform = font->info.transform && mode != FT_RENDER_MODE_MONO; ++ + while (nglyph--) + { + glyphindex = *glyphs++; +@@ -440,7 +617,7 @@ 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. +@@ -487,7 +664,7 @@ XftFontLoadGlyphs (Display *dpy, + * 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) + { +@@ -519,18 +696,20 @@ XftFontLoadGlyphs (Display *dpy, + } + } + ++ 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) + { +@@ -613,14 +792,27 @@ XftFontLoadGlyphs (Display *dpy, + } + } + +- size = _compute_xrender_bitmap_size( &local, glyphslot, mode ); ++ size = _compute_xrender_bitmap_size( &local, glyphslot, mode, glyph_transform ? &font->info.matrix : NULL ); + 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 (transform) ++ { ++ vector.x = - glyphslot->bitmap_left; ++ vector.y = glyphslot->bitmap_top; ++ ++ FT_Vector_Transform(&vector, &font->info.matrix); ++ ++ 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), +@@ -645,9 +837,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, &font->info.matrix); ++ 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,6 +857,7 @@ XftFontLoadGlyphs (Display *dpy, + */ + glyph = (Glyph) glyphindex; + ++ xftg->picture = 0; + xftg->glyph_memory = (size_t)size + sizeof (XftGlyph); + if (font->format) + { +@@ -685,15 +881,21 @@ 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) ++ xftg->picture = _create_glyph_bgra_picture(dpy, font->format, ++ local.width, local.rows, ++ bufBitmap); ++ else ++ XRenderAddGlyphs (dpy, font->glyphset, &glyph, ++ &xftg->metrics, 1, ++ (char *) bufBitmap, size); + } + else + { +@@ -744,7 +946,9 @@ XftFontUnloadGlyphs (Display *dpy, + { + 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])) +diff --git a/src/xftint.h b/src/xftint.h +index ced9a02..1af40fe 100644 +--- a/src/xftint.h ++++ b/src/xftint.h +@@ -85,6 +85,7 @@ typedef struct _XftGlyph { + XGlyphInfo metrics; + void *bitmap; + unsigned long glyph_memory; ++ Picture picture; + } XftGlyph; + + /* +@@ -134,6 +135,7 @@ struct _XftFontInfo { + FT_F26Dot6 xsize, ysize; /* pixel size */ + FcBool antialias; /* doing antialiasing */ + FcBool embolden; /* force emboldening */ ++ FcBool color; /* contains color glyphs */ + int rgba; /* subpixel order */ + int lcd_filter; /* lcd filter */ + FT_Matrix matrix; /* glyph transformation matrix */ +diff --git a/src/xftrender.c b/src/xftrender.c +index 5852b2e..bd001be 100644 +--- a/src/xftrender.c ++++ b/src/xftrender.c +@@ -84,12 +84,14 @@ XftGlyphRender (Display *dpy, + int nglyphs) + { + XftFontInt *font = (XftFontInt *) pub; +- int i; ++ int i, j; + FT_UInt missing[XFT_NMISSING]; + int nmissing; + FT_UInt g, max; + int size, width; ++ int dstx, dsty; + Glyph wire; ++ XftGlyph* glyph; + char *char8; + unsigned short *char16; + unsigned int *char32; +@@ -141,22 +143,46 @@ XftGlyphRender (Display *dpy, + if (!chars) + goto bail1; + } ++ dstx = x; ++ dsty = y; + char8 = (char *) chars; + char16 = (unsigned short *) chars; + char32 = (unsigned int *) chars; +- for (i = 0; i < nglyphs; i++) ++ for (i = 0, j = 0; i < nglyphs; i++) + { + wire = (Glyph) glyphs[i]; + if (wire >= font->num_glyphs || !font->glyphs[wire]) + wire = 0; +- switch (width) { +- case 1: char8[i] = (char) wire; break; +- case 2: char16[i] = (unsigned short) wire; break; +- case 4: char32[i] = (unsigned int) wire; break; ++ glyph = font->glyphs[wire]; ++ if (glyph->picture) ++ { ++ _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset, ++ srcx, srcy, x, y, width, chars, j); ++ XRenderComposite(dpy, PictOpOver, glyph->picture, None, ++ dst, 0, 0, 0, 0, dstx, dsty - glyph->metrics.y, ++ glyph->metrics.width, glyph->metrics.height); ++ ++ dstx += glyph->metrics.xOff; ++ dsty += glyph->metrics.yOff; ++ ++ x = dstx; ++ y = dsty; ++ j = 0; ++ } ++ else ++ { ++ switch (width) { ++ case 1: char8[j] = (char) wire; break; ++ case 2: char16[j] = (unsigned short) wire; break; ++ case 4: char32[j] = (unsigned int) wire; break; ++ } ++ dstx += glyph->metrics.xOff; ++ dsty += glyph->metrics.yOff; ++ ++j; + } + } + _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset, +- srcx, srcy, x, y, width, chars, nglyphs); ++ srcx, srcy, x, y, width, chars, j); + if (chars != char_local) + free (chars); + bail1: +@@ -319,9 +345,10 @@ XftGlyphSpecRender (Display *dpy, + g = 0; + /* + * check to see if the glyph is placed where it would +- * fall using the normal spacing ++ * fall using the normal spacing and if it would render ++ * as a XRender glyph + */ +- if ((glyph = font->glyphs[g])) ++ if ((glyph = font->glyphs[g]) && !glyph->picture) + { + if (x != glyphs[i].x || y != glyphs[i].y) + { +@@ -335,7 +362,7 @@ XftGlyphSpecRender (Display *dpy, + } + + elts = elts_local; +- if (nelt > NUM_ELT_LOCAL) ++ if (!font->info.color && nelt > NUM_ELT_LOCAL) + { + elts = malloc ((size_t)nelt * sizeof (XGlyphElt8)); + if (!elts) +@@ -343,7 +370,7 @@ XftGlyphSpecRender (Display *dpy, + } + + /* +- * Generate the list of glyph elts ++ * Generate the list of glyph elts or render color glyphs + */ + nelt = 0; + x = y = 0; +@@ -357,6 +384,14 @@ XftGlyphSpecRender (Display *dpy, + g = 0; + if ((glyph = font->glyphs[g])) + { ++ if (glyph->picture) ++ { ++ XRenderComposite(dpy, PictOpOver, glyph->picture, None, ++ dst, 0, 0, 0, 0, ++ glyphs[i].x, glyphs[i].y - glyph->metrics.y, ++ glyph->metrics.width, glyph->metrics.height); ++ continue; ++ } + if (!i || x != glyphs[i].x || y != glyphs[i].y) + { + if (n) +@@ -589,7 +624,7 @@ XftGlyphFontSpecRender (Display *dpy, + * check to see if the glyph is placed where it would + * fall using the normal spacing + */ +- if ((glyph = font->glyphs[g])) ++ if ((glyph = font->glyphs[g]) && !glyph->picture) + { + if (pub != prevPublic || x != glyphs[i].x || y != glyphs[i].y) + { +@@ -614,7 +649,7 @@ XftGlyphFontSpecRender (Display *dpy, + } + + /* +- * Generate the list of glyph elts ++ * Generate the list of glyph elts and render color glyphs + */ + nelt = 0; + x = y = 0; +@@ -632,6 +667,14 @@ XftGlyphFontSpecRender (Display *dpy, + g = 0; + if ((glyph = font->glyphs[g])) + { ++ if (glyph->picture) ++ { ++ XRenderComposite(dpy, PictOpOver, glyph->picture, None, ++ dst, 0, 0, 0, 0, ++ glyphs[i].x, glyphs[i].y - glyph->metrics.y, ++ glyph->metrics.width, glyph->metrics.height); ++ continue; ++ } + if (!i || pub != prevPublic || x != glyphs[i].x || y != glyphs[i].y) + { + if (n) +-- +2.32.0 +