From 3ca7a7c375a8c022c068e2534c5a6861e547eaef Mon Sep 17 00:00:00 2001 From: "Thomas E. Dickey" Date: Sat, 9 Jul 2022 09:04:18 -0400 Subject: merge changes by Christian Werner see note in libXft merge-request #1 at #note_1222314 Signed-off-by: Thomas E. Dickey --- src/xftfreetype.c | 19 +++- src/xftglyphs.c | 333 +++++++++++++++++++++++++++++++++--------------------- src/xftrender.c | 21 ++-- 3 files changed, 234 insertions(+), 139 deletions(-) diff --git a/src/xftfreetype.c b/src/xftfreetype.c index 51d4613..b2e09e2 100644 --- a/src/xftfreetype.c +++ b/src/xftfreetype.c @@ -367,10 +367,10 @@ XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi) { XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); FcChar8 *filename; - int id; + int id, mid; double dsize; double aspect; - FcMatrix *font_matrix; + FcMatrix *font_matrix, fm1; FcBool hinting, vertical_layout, autohint, global_advance; int hint_style; FcChar32 hash, *hashp; @@ -491,6 +491,21 @@ XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi) goto bail1; } + mid = 1; + while (FcPatternGetMatrix (pattern, FC_MATRIX, mid, &font_matrix) == FcResultMatch) { + FcMatrixInit(&fm1); + fm1.xx = fi->matrix.xx / (double) 0x10000L; + fm1.yy = fi->matrix.yy / (double) 0x10000L; + fm1.xy = fi->matrix.xy / (double) 0x10000L; + fm1.yx = fi->matrix.yx / (double) 0x10000L; + FcMatrixMultiply(&fm1, font_matrix, &fm1); + fi->matrix.xx = (FT_Fixed)(0x10000L * fm1.xx); + fi->matrix.yy = (FT_Fixed)(0x10000L * fm1.yy); + fi->matrix.xy = (FT_Fixed)(0x10000L * fm1.xy); + fi->matrix.yx = (FT_Fixed)(0x10000L * fm1.yx); + mid++; + } + fi->transform = (fi->matrix.xx != 0x10000 || fi->matrix.xy != 0 || fi->matrix.yx != 0 || fi->matrix.yy != 0x10000); diff --git a/src/xftglyphs.c b/src/xftglyphs.c index 2e2ba67..a893394 100644 --- a/src/xftglyphs.c +++ b/src/xftglyphs.c @@ -29,6 +29,46 @@ #include FT_GLYPH_H +typedef double m3x3[3][3]; + +static inline 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 inline 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 inline 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 */ @@ -144,10 +184,10 @@ static int _compute_xrender_bitmap_size( FT_Bitmap* target, FT_GlyphSlot slot, FT_Render_Mode mode, - FT_Matrix* matrix ) + FT_Matrix* matrix, + m3x3 m ) { FT_Bitmap* ftbit; - FT_Vector vector; int width, height, pitch; if ( slot->format != FT_GLYPH_FORMAT_BITMAP ) @@ -161,12 +201,59 @@ _compute_xrender_bitmap_size( FT_Bitmap* target, 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; + 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 = vector.x; + bottom = vector.y; + vector.x = width; + vector.y = height; + FT_Vector_Transform(&vector, &inverse); + right = vector.x; + top = 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; @@ -238,8 +325,8 @@ _compute_xrender_bitmap_size( FT_Bitmap* target, */ static void _scaled_fill_xrender_bitmap( FT_Bitmap* target, - FT_Bitmap* source, - const FT_Matrix* matrix ) + FT_Bitmap* source, + m3x3 m ) { unsigned char* src_buf = source->buffer; unsigned char* dst_line = target->buffer; @@ -247,44 +334,55 @@ _scaled_fill_xrender_bitmap( FT_Bitmap* target, int width = (int) target->width; int height = (int) target->rows; int pitch = target->pitch; - int h; - FT_Vector vector; - FT_Matrix inverse = *matrix; + int i, x, y; + FT_Vector vector, vector0; int sampling_width; int sampling_height; int sample_count; if ( src_pitch < 0 ) - src_buf -= src_pitch * ((int) source->rows - 1); - - FT_Matrix_Invert(&inverse); + src_buf -= src_pitch*(source->rows-1); /* compute how many source pixels a target pixel spans */ vector.x = 1; vector.y = 1; - FT_Vector_Transform(&vector, &inverse); - sampling_width = (int) vector.x / 2; - sampling_height = (int) vector.y / 2; + m3x3_transform(&vector, m); + vector0.x = 0; + vector0.y = 0; + m3x3_transform(&vector0, m); + sampling_width = (vector.x - vector0.x) / 2; + sampling_height = (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 ( h = height; h > 0; h--, dst_line += pitch ) + for ( y = height; y > 0; y--, dst_line += pitch ) { - int x; - - for ( x = 0; x < width; x++ ) + for ( x = 0; x < width; x++ ) { unsigned char* src; -#define CLAMP(x, min, max) (int) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x))) + /* compute target pixel location in source space */ + vector.x = x; + vector.y = height - y; + m3x3_transform(&vector, m); - /* 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); + if (source->pixel_mode == FT_PIXEL_MODE_BGRA) + { + if (vector.x < -sampling_width || vector.x > source->width + sampling_width) + continue; + if (vector.y < -sampling_height || vector.y > source->rows + 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 ) + 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); @@ -300,22 +398,28 @@ _scaled_fill_xrender_bitmap( FT_Bitmap* target, 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}; - int i; + int bgra[4] = { 0, 0, 0, 0 }; + for (sample_y = - sampling_height; sample_y < sampling_height + 1; ++sample_y) { - int src_y = CLAMP(vector.y + sample_y, 0, source->rows - 1); + int src_y = vector.y + sample_y; + + if (src_y < 0 || 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 = CLAMP(vector.x + sample_x, 0, source->width - 1); + int src_x = vector.x + sample_x; + + if (src_x < 0 || 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); + dst_line[4 * x + i] = bgra[i] / sample_count; break; } } @@ -347,15 +451,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; - - subpixel = ( mode == FT_RENDER_MODE_LCD || + 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 || mode == FT_RENDER_MODE_LCD_V ); if ( src_pitch < 0 ) @@ -525,55 +629,6 @@ _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, - unsigned width, - unsigned height, - unsigned char *data) -{ - XImage image = { - (int) width, (int) height, 0, ZPixmap, (char *)data, - dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32, - 32, 0, 32, - 0, 0, 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, @@ -598,6 +653,7 @@ 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; @@ -612,7 +668,7 @@ XftFontLoadGlyphs (Display *dpy, return; if (font->info.color) - mode = FT_RENDER_MODE_NORMAL; + mode = FT_RENDER_MODE_NORMAL; if (font->info.antialias) { switch (font->info.rgba) { @@ -688,22 +744,22 @@ XftFontLoadGlyphs (Display *dpy, */ 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; } } @@ -711,7 +767,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 ); @@ -780,9 +836,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 { @@ -851,19 +907,21 @@ XftFontLoadGlyphs (Display *dpy, } } - size = _compute_xrender_bitmap_size( &local, glyphslot, mode, glyph_transform ? &font->info.matrix : NULL ); + 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; - if (transform) + if (glyph_transform) { + m3x3 mi; + + m3x3_invert(m, mi); vector.x = - glyphslot->bitmap_left; vector.y = glyphslot->bitmap_top; - - FT_Vector_Transform(&vector, &font->info.matrix); - + m3x3_transform(&vector, mi); xftg->metrics.x = (short)vector.x; xftg->metrics.y = (short)vector.y; } @@ -896,12 +954,12 @@ XftFontLoadGlyphs (Display *dpy, local.buffer = bufBitmap; - if (mode == FT_RENDER_MODE_NORMAL && glyph_transform) - _scaled_fill_xrender_bitmap(&local, &glyphslot->bitmap, &font->info.matrix); - else + 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 ) ); + (font->info.rgba == FC_RGBA_BGR || + font->info.rgba == FC_RGBA_VBGR) ); /* * Copy or convert into local buffer. @@ -916,7 +974,11 @@ XftFontLoadGlyphs (Display *dpy, */ glyph = (Glyph) glyphindex; - xftg->picture = 0; + if (xftg->picture) + { + XRenderFreePicture(dpy, xftg->picture); + xftg->picture = 0; + } xftg->glyph_memory = (size_t)size + font->sizeof_glyph; if (font->format) { @@ -948,10 +1010,31 @@ XftFontLoadGlyphs (Display *dpy, } if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) - xftg->picture = _create_glyph_bgra_picture(dpy, font->format, - local.width, - local.rows, - bufBitmap); + { + Pixmap pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), local.width, local.rows, 32); + GC gc = XCreateGC(dpy, pixmap, 0, NULL); + XImage image = { + local.width, local.rows, 0, ZPixmap, (char *)bufBitmap, + dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32, + 32, local.width * 4 - local.pitch, 32, + 0, 0, 0 + }; + + 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 - size; + else + xftg->glyph_memory += (size_t)size * 255; + } else XRenderAddGlyphs (dpy, font->glyphset, &glyph, &xftg->metrics, 1, @@ -1059,11 +1142,8 @@ 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; @@ -1140,6 +1220,7 @@ XftFontCheckGlyph (Display *dpy, xftg->bitmap = NULL; xftg->glyph_memory = 0; + xftg->picture = 0; font->glyphs[glyph] = xftg; if (font->track_mem_usage) { diff --git a/src/xftrender.c b/src/xftrender.c index 721cae0..98c86cd 100644 --- a/src/xftrender.c +++ b/src/xftrender.c @@ -156,15 +156,10 @@ XftGlyphRender (Display *dpy, 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); - + _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 - glyph->metrics.x, dsty - glyph->metrics.y, glyph->metrics.width, glyph->metrics.height); dstx += glyph->metrics.xOff; dsty += glyph->metrics.yOff; - x = dstx; y = dsty; j = 0; @@ -388,8 +383,10 @@ XftGlyphSpecRender (Display *dpy, { 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); + glyphs[i].x - glyph->metrics.x, + glyphs[i].y - glyph->metrics.y, + glyph->metrics.width, + glyph->metrics.height); continue; } if (!i || x != glyphs[i].x || y != glyphs[i].y) @@ -674,8 +671,10 @@ XftGlyphFontSpecRender (Display *dpy, { 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); + glyphs[i].x - glyph->metrics.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) -- cgit v1.2.1