862 lines
25 KiB
Diff
862 lines
25 KiB
Diff
From 723092ece088559f1af299236305911f4ee4d450 Mon Sep 17 00:00:00 2001
|
|
From: Maxime Coste <mawww@kakoune.org>
|
|
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 <mawww@kakoune.org>
|
|
---
|
|
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:
|
|
--
|
|
GitLab
|
|
|
|
|
|
From e0fc4ce7e87ab9c4b47e5c8e693f070dfd0d2f7b Mon Sep 17 00:00:00 2001
|
|
From: Maxime Coste <mawww@kakoune.org>
|
|
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 <mawww@kakoune.org>
|
|
---
|
|
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);
|
|
--
|
|
GitLab
|
|
|
|
|
|
From d385aa3e5320d18918413df0e8aef3a713a47e0b Mon Sep 17 00:00:00 2001
|
|
From: Maxime Coste <mawww@kakoune.org>
|
|
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 <mawww@kakoune.org>
|
|
---
|
|
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)
|
|
--
|
|
GitLab
|
|
|