ppisar pushed to perl-Prima (f22). "Fix XFT font handling"
notifications at fedoraproject.org
notifications at fedoraproject.org
Tue Oct 27 18:08:51 UTC 2015
From c284b74408ab2c40ef2140684398f49f5ad7fc8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar at redhat.com>
Date: Tue, 27 Oct 2015 19:08:13 +0100
Subject: Fix XFT font handling
---
...rehaul-of-xft-for-testing-of-corner-cases.patch | 792 +++++++++++++++++++++
perl-Prima.spec | 8 +-
2 files changed, 799 insertions(+), 1 deletion(-)
create mode 100644 Prima-1.42-rehaul-of-xft-for-testing-of-corner-cases.patch
diff --git a/Prima-1.42-rehaul-of-xft-for-testing-of-corner-cases.patch b/Prima-1.42-rehaul-of-xft-for-testing-of-corner-cases.patch
new file mode 100644
index 0000000..bcfe97c
--- /dev/null
+++ b/Prima-1.42-rehaul-of-xft-for-testing-of-corner-cases.patch
@@ -0,0 +1,792 @@
+From 4b485cca8733dc91ee7b8f87fe34728fb6d2c2ce Mon Sep 17 00:00:00 2001
+From: Dmitry Karasik <dmka at novozymes.com>
+Date: Tue, 31 Mar 2015 17:22:50 +0200
+Subject: [PATCH] rehaul of xft for testing of corner cases
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Petr Pisar: Ported to 1.42:
+
+6695af5aa870c94e17fdd36a01e9fda513597567 is the first bad commit
+commit 6695af5aa870c94e17fdd36a01e9fda513597567
+Author: Dmitry Karasik <dmka at novozymes.com>
+Date: Tue Mar 31 17:22:50 2015 +0200
+
+ rehaul of xft for testing of corner cases
+
+Signed-off-by: Petr Písař <ppisar at redhat.com>
+---
+ include/unix/guts.h | 3 +-
+ unix/apc_font.c | 2 +-
+ unix/xft.c | 421 ++++++++++++++++++++++++++++------------------------
+ 3 files changed, 234 insertions(+), 192 deletions(-)
+
+diff --git a/include/unix/guts.h b/include/unix/guts.h
+index 72e0e09..2f2a02d 100644
+--- a/include/unix/guts.h
++++ b/include/unix/guts.h
+@@ -462,6 +462,7 @@ prima_debug( const char *format, ...);
+ #define Mdebug if (pguts->debug & DEBUG_MISC) _debug
+ #define Pdebug if (pguts->debug & DEBUG_COLOR) _debug
+ #define Xdebug if (pguts->debug & DEBUG_XRDB) _debug
++#define _F_DEBUG_PITCH(x) ((x==fpDefault)?"default":(x==fpFixed?"fixed":"variable"))
+
+ typedef struct _UnixGuts
+ {
+@@ -1191,7 +1192,7 @@ extern void
+ prima_xft_done( void);
+
+ extern Bool
+-prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size);
++prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size, XftFont ** xft_result);
+
+ extern Bool
+ prima_xft_set_font( Handle self, PFont font);
+diff --git a/unix/apc_font.c b/unix/apc_font.c
+index 607ad98..4e1daca 100644
+--- a/unix/apc_font.c
++++ b/unix/apc_font.c
+@@ -1582,7 +1582,7 @@ apc_font_pick( Handle self, PFont source, PFont dest)
+ {
+ #ifdef USE_XFT
+ if ( guts. use_xft) {
+- if ( prima_xft_font_pick( self, source, dest, nil))
++ if ( prima_xft_font_pick( self, source, dest, nil, nil))
+ return true;
+ }
+ #endif
+diff --git a/unix/xft.c b/unix/xft.c
+index 25a5aea..eefbbe2 100644
+--- a/unix/xft.c
++++ b/unix/xft.c
+@@ -97,6 +97,9 @@
+ #define NEED_EXPLICIT_FC_SCALABLE 1
+ #endif
+
++static int xft_debug_indent = 0;
++#define XFTdebug if (pguts->debug & DEBUG_FONTS) xft_debug
++
+ typedef struct {
+ char *name;
+ FcCharSet *fcs;
+@@ -152,6 +155,20 @@ extern XExtDisplayInfo *
+ XRenderFindDisplay (Display *dpy);
+ #endif
+
++static void
++xft_debug( const char *format, ...)
++{
++ int i;
++ va_list args;
++ va_start( args, format);
++ fprintf( stderr, "xft: ");
++ for ( i = 0; i < xft_debug_indent * 3; i++) fprintf( stderr, " ");
++ vfprintf( stderr, format, args);
++ fprintf( stderr, "\n");
++ va_end( args);
++}
++
++
+ void
+ prima_xft_init(void)
+ {
+@@ -183,7 +200,7 @@ prima_xft_init(void)
+ }
+ /* After this point guts.use_xft must never be altered */
+ if ( !guts. use_xft) return;
+- Fdebug("XFT ok\n");
++ XFTdebug("XFT ok");
+
+ csi = std_charsets;
+ fcs_ascii = FcCharSetCreate();
+@@ -314,7 +331,7 @@ fcpattern2font( FcPattern * pattern, PFont font)
+ {
+ FcChar8 * s;
+ int i, j;
+- double d = 1.0;
++ double d = 1.0, ds;
+ FcCharSet *c = nil;
+
+ /* FcPatternPrint( pattern); */
+@@ -330,32 +347,40 @@ fcpattern2font( FcPattern * pattern, PFont font)
+ else if ( i >= FC_WEIGHT_BOLD)
+ font-> style |= fsBold;
+ }
++
+ if ( FcPatternGetInteger( pattern, FC_SPACING, 0, &i) == FcResultMatch)
+ font-> pitch = (( i == FC_PROPORTIONAL) ? fpVariable : fpFixed);
+
+- if ( FcPatternGetInteger( pattern, FC_PIXEL_SIZE, 0, &font-> height) == FcResultMatch) {
+- Fdebug("xft:height factor read:%d\n", font-> height);
++ if ( FcPatternGetDouble( pattern, FC_PIXEL_SIZE, 0, &d) == FcResultMatch) {
++ font->height = d + 0.5;
++ XFTdebug("height factor read:%d (%g)", font-> height, d);
+ }
++
+ font-> width = 100; /* warning, FC_WIDTH does not reflect FC_MATRIX scale changes */
+- if ( FcPatternGetInteger( pattern, FC_WIDTH, 0, &font-> width) == FcResultMatch) {
+- Fdebug("xft:width factor read:%d\n", font-> width);
++ if ( FcPatternGetDouble( pattern, FC_WIDTH, 0, &d) == FcResultMatch) {
++ font->width = d + 0.5;
++ XFTdebug("width factor read:%d (%g)", font-> width, d);
+ }
+ font-> width = ( font-> width * font-> height) / 100.0 + .5;
+- font-> yDeviceRes = guts. resolution. y;
+- FcPatternGetInteger( pattern, FC_DPI, 0, &font-> yDeviceRes);
+- if ( font-> yDeviceRes <= 0)
+- font-> yDeviceRes = guts. resolution. y;
+- FcPatternGetBool( pattern, FC_SCALABLE, 0, &font-> vector);
+- FcPatternGetDouble( pattern, FC_ASPECT, 0, &d);
+- font-> xDeviceRes = font-> yDeviceRes * d;
+- if (
+- (FcPatternGetInteger( pattern, FC_SIZE, 0, &font-> size) != FcResultMatch) &&
+- (font-> height != C_NUMERIC_UNDEF)
+- ) {
++
++ if ( FcPatternGetDouble( pattern, FC_SIZE, 0, &d) == FcResultMatch) {
++ font->size = d + 0.5;
++ XFTdebug("size factor read:%d (%g)", font-> size, d);
++ } else if (font-> height != C_NUMERIC_UNDEF && font->yDeviceRes != 0) {
+ font-> size = font-> height * 72.27 / font-> yDeviceRes + .5;
+- Fdebug("xft:size calculated:%d\n", font-> size);
++ XFTdebug("size calculated:%d", font-> size);
++ } else {
++ XFTdebug("size unknown");
+ }
+
++ font-> xDeviceRes = guts. resolution. x;
++ font-> yDeviceRes = guts. resolution. y;
++ if ( FcPatternGetDouble( pattern, FC_DPI, 0, &d) == FcResultMatch)
++ font-> yDeviceRes = d + 0.5;
++ if ( FcPatternGetDouble( pattern, FC_ASPECT, 0, &d) == FcResultMatch)
++ font-> xDeviceRes = font-> yDeviceRes * d;
++ FcPatternGetBool( pattern, FC_SCALABLE, 0, &font-> vector);
++
+ font-> firstChar = 32; font-> lastChar = 255;
+ font-> breakChar = 32; font-> defaultChar = 32;
+ if (( FcPatternGetCharSet( pattern, FC_CHARSET, 0, &c) == FcResultMatch) && c) {
+@@ -410,17 +435,18 @@ xft_build_font_key( PFontKey key, PFont f, Bool bySize)
+ strcpy( key-> name, f-> name);
+ }
+
+-static PCachedFont
++static XftFont *
+ try_size( Handle self, Font f, double size)
+ {
+ FontKey key;
+- f. size = size;
++ XftFont * xft = nil;
++ f. size = size + 0.5;
+ f. height = f. width = C_NUMERIC_UNDEF;
+ f. direction = 0;
+- if ( !prima_xft_font_pick( self, &f, &f, &size)) return nil;
+- f. width = 0;
+- xft_build_font_key( &key, &f, true);
+- return ( PCachedFont) hash_fetch( guts. font_hash, &key, sizeof( FontKey));
++ xft_debug_indent++;
++ prima_xft_font_pick( self, &f, &f, &size, &xft);
++ xft_debug_indent--;
++ return xft;
+ }
+
+ /* find a most similar monospace/proportional font by name and family */
+@@ -509,54 +535,81 @@ find_good_font_by_family( Font * f, int fc_spacing )
+ }
+ }
+
++static void
++xft_store_font(Font * k, Font * v, Bool by_size, XftFont * xft, XftFont * xft_base)
++{
++ FontKey key;
++ PCachedFont kf;
++ xft_build_font_key( &key, k, by_size);
++ if ( !hash_fetch( guts. font_hash, &key, sizeof(FontKey))) {
++ if (( kf = malloc( sizeof( CachedFont)))) {
++ bzero( kf, sizeof( CachedFont));
++ memcpy( &kf-> font, v, sizeof( Font));
++ kf-> font. style &= ~(fsUnderlined|fsOutline|fsStruckOut);
++ kf-> xft = xft;
++ kf-> xft_base = xft_base;
++ hash_store( guts. font_hash, &key, sizeof( FontKey), kf);
++ XFTdebug("store %x(%x):%dx%d.%x.%s.%s", xft, xft_base, key.height, key.width, key.style, _F_DEBUG_PITCH(key.pitch), key.name);
++ }
++ }
++}
++
+ static int force_xft_monospace_emulation = 0;
+
+ Bool
+-prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
++prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size, XftFont ** xft_result)
+ {
+ FcPattern *request, *match;
+ FcResult res = FcResultNoMatch;
+- Font f, f1;
++ Font requested_font, loaded_font;
+ Bool by_size;
+ CharSetInfo * csi;
+ XftFont * xf;
+ FontKey key;
+ PCachedFont kf, kf_base = nil;
+- int i, base_width = 1, pixel_size, exact_pixel_size = 0;
++ int i, base_width = 1, exact_pixel_size = 0, cache_results = 1;
++ double pixel_size;
+
+ if ( !guts. use_xft) return false;
+
+- f = *dest;
+- by_size = Drawable_font_add( self, source, &f);
+- pixel_size = f. height;
++ requested_font = *dest;
++ by_size = Drawable_font_add( self, source, &requested_font);
++ pixel_size = requested_font. height;
+
+ if ( guts. xft_disable_large_fonts > 0) {
+ /* xft is unable to deal with large polygon requests.
+ we must cut the large fonts here, before Xlib croaks */
+ if (
+- ( by_size && ( f. size >= MAX_GLYPH_SIZE)) ||
+- (!by_size && ( f. height >= MAX_GLYPH_SIZE / 72.27 * guts. resolution. y))
++ ( by_size && ( requested_font. size >= MAX_GLYPH_SIZE)) ||
++ (!by_size && ( requested_font. height >= MAX_GLYPH_SIZE / 72.27 * guts. resolution. y))
+ )
+ return false;
+ }
+
++ /* we don't want to cache fractional sizes because these can lead to incoherent results
++ depending on whether we match a particular height by size or by height */
++ if ( by_size && size && *size * 100 != requested_font.size * 100 ) {
++ cache_results = 0;
++ XFTdebug("not caching results because size %g is fractional", *size);
++ }
++
+ /* see if the font is not present in xft - the hashed negative matches
+ are stored with width=0, as the width alterations are derived */
+- xft_build_font_key( &key, &f, by_size);
+- Fdebug("xft:want %d.%d.%d.%d.%s\n", key.height, key. width, key.style, key.pitch, key.name);
++ xft_build_font_key( &key, &requested_font, by_size);
++ XFTdebug("want %dx%d.%x.%s.%s/%s", key.height, key. width, key.style, _F_DEBUG_PITCH(key.pitch), key.name, requested_font.encoding);
+
+ key. width = 0;
+ if ( hash_fetch( mismatch, &key, sizeof( FontKey))) {
+- Fdebug("xft: refuse\n");
++ XFTdebug("refuse");
+ return false;
+ }
+- key. width = f. width;
++ key. width = requested_font. width;
+
+ /* convert encoding */
+- csi = ( CharSetInfo*) hash_fetch( encodings, f. encoding, strlen( f. encoding));
++ csi = ( CharSetInfo*) hash_fetch( encodings, requested_font. encoding, strlen( requested_font. encoding));
+ if ( !csi) {
+ /* xft has no such encoding, pass it back */
+- if ( prima_core_font_encoding( f. encoding) || !guts. xft_priority)
++ if ( prima_core_font_encoding( requested_font. encoding) || !guts. xft_priority)
+ return false;
+ csi = locale;
+ }
+@@ -565,8 +618,8 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ if (( kf = hash_fetch( guts. font_hash, &key, sizeof( FontKey)))) {
+ *dest = kf-> font;
+ strcpy( dest-> encoding, csi-> name);
+- if ( f. style & fsStruckOut) dest-> style |= fsStruckOut;
+- if ( f. style & fsUnderlined) dest-> style |= fsUnderlined;
++ if ( requested_font. style & fsStruckOut) dest-> style |= fsStruckOut;
++ if ( requested_font. style & fsUnderlined) dest-> style |= fsUnderlined;
+ return true;
+ }
+ /* see if the non-xscaled font exists */
+@@ -575,65 +628,80 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ if ( !( kf = hash_fetch( guts. font_hash, &key, sizeof( FontKey)))) {
+ Font s = *source, d = *dest;
+ s. width = d. width = 0;
+- prima_xft_font_pick( self, &s, &d, size);
++ XFTdebug("try nonscaled font");
++ xft_debug_indent++;
++ prima_xft_font_pick( self, &s, &d, size, nil);
++ xft_debug_indent--;
+ }
+ if ( kf || ( kf = hash_fetch( guts. font_hash, &key, sizeof( FontKey)))) {
+ base_width = kf-> font. width;
+- if ( FcPatternGetInteger( kf-> xft-> pattern, FC_PIXEL_SIZE, 0, &pixel_size) == FcResultMatch)
++ if ( FcPatternGetDouble( kf-> xft-> pattern, FC_PIXEL_SIZE, 0, &pixel_size) == FcResultMatch) {
+ exact_pixel_size = 1;
++ XFTdebug("existing base font %x %dx0 suggests exact_pixel_size %g base_width %d", kf->xft, key.height, pixel_size, base_width);
++ }
+ } else { /* if fails, cancel x scaling and see if it failed due to banning */
+ if ( hash_fetch( mismatch, &key, sizeof( FontKey))) return false;
+- f. width = 0;
++ requested_font. width = 0;
+ }
+ }
+ /* see if the non-rotated font exists */
+ if ( key. direction != 0) {
+ key. direction = 0;
+- key. width = f. width;
++ key. width = requested_font. width;
+ if ( !( kf_base = hash_fetch( guts. font_hash, &key, sizeof( FontKey)))) {
+ Font s = *source, d = *dest;
+ s. direction = d. direction = 0;
+- prima_xft_font_pick( self, &s, &d, size);
++ XFTdebug("try nonrotated font");
++ xft_debug_indent++;
++ prima_xft_font_pick( self, &s, &d, size, nil);
++ xft_debug_indent--;
+ /* if fails, cancel rotation and see if the base font is banned */
+ if ( !( kf_base = hash_fetch( guts. font_hash, &key, sizeof( FontKey))))
+- f. direction = 0;
++ requested_font. direction = 0;
+ }
+- if ( f. direction != 0) {
+- /* as f. height != FC_PIXEL_SIZE, read the correct request
++ if ( requested_font. direction != 0) {
++ /* as requested_font. height != FC_PIXEL_SIZE, read the correct request
+ from the non-rotated font */
+- if ( FcPatternGetInteger( kf_base-> xft-> pattern, FC_PIXEL_SIZE, 0, &pixel_size) == FcResultMatch)
++ if ( FcPatternGetDouble( kf_base-> xft-> pattern, FC_PIXEL_SIZE, 0, &pixel_size) == FcResultMatch) {
++ XFTdebug("existing base font %x %dx%d dir=0 suggests exact_pixel_size %g", kf_base->xft, key.height, key.width, pixel_size);
+ exact_pixel_size = 1;
++ }
+ }
+ }
+
+ /* create FcPattern request */
+ if ( !( request = FcPatternCreate())) return false;
+- if ( strcmp( f. name, "Default") != 0)
+- FcPatternAddString( request, FC_FAMILY, ( FcChar8*) f. name);
++ if ( strcmp( requested_font. name, "Default") != 0)
++ FcPatternAddString( request, FC_FAMILY, ( FcChar8*) requested_font. name);
+ if ( by_size) {
+- if ( size)
++ if ( size) {
+ FcPatternAddDouble( request, FC_SIZE, *size);
+- else
+- FcPatternAddInteger( request, FC_SIZE, f. size);
+- } else
+- FcPatternAddInteger( request, FC_PIXEL_SIZE, pixel_size);
++ XFTdebug("FC_SIZE = %.1f", *size);
++ } else {
++ FcPatternAddInteger( request, FC_SIZE, requested_font. size);
++ XFTdebug("FC_SIZE = %d", requested_font. size);
++ }
++ } else {
++ FcPatternAddDouble( request, FC_PIXEL_SIZE, pixel_size);
++ XFTdebug("FC_PIXEL_SIZE = %g", pixel_size);
++ }
+ FcPatternAddInteger( request, FC_SPACING,
+- (f. pitch == fpFixed && force_xft_monospace_emulation) ? FC_MONO : FC_PROPORTIONAL);
++ (requested_font. pitch == fpFixed && force_xft_monospace_emulation) ? FC_MONO : FC_PROPORTIONAL);
+
+- FcPatternAddInteger( request, FC_SLANT, ( f. style & fsItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
++ FcPatternAddInteger( request, FC_SLANT, ( requested_font. style & fsItalic) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
+ FcPatternAddInteger( request, FC_WEIGHT,
+- ( f. style & fsBold) ? FC_WEIGHT_BOLD :
+- ( f. style & fsThin) ? FC_WEIGHT_THIN : FC_WEIGHT_NORMAL);
++ ( requested_font. style & fsBold) ? FC_WEIGHT_BOLD :
++ ( requested_font. style & fsThin) ? FC_WEIGHT_THIN : FC_WEIGHT_NORMAL);
+ #ifdef NEED_EXPLICIT_FC_SCALABLE
+ FcPatternAddInteger( request, FC_SCALABLE, 1);
+ #endif
+- if ( f. direction != 0 || f. width != 0) {
++ if ( requested_font. direction != 0 || requested_font. width != 0) {
+ FcMatrix mat;
+ FcMatrixInit(&mat);
+- if ( f. width != 0)
+- FcMatrixScale( &mat, ( double) f. width / base_width, 1);
+- if ( f. direction != 0)
+- FcMatrixRotate( &mat, cos(f.direction * 3.14159265358 / 180.0), sin(f.direction * 3.14159265358 / 180.0));
++ if ( requested_font. width != 0)
++ FcMatrixScale( &mat, ( double) requested_font. width / base_width, 1);
++ if ( requested_font. direction != 0)
++ FcMatrixRotate( &mat, cos(requested_font.direction * 3.14159265358 / 180.0), sin(requested_font.direction * 3.14159265358 / 180.0));
+ FcPatternAddMatrix( request, FC_MATRIX, &mat);
+ }
+
+@@ -643,17 +711,18 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ /* match best font - must return something useful; the match is statically allocated */
+ match = XftFontMatch( DISP, SCREEN, request, &res);
+ if ( !match) {
+- Fdebug("xft: XftFontMatch error\n");
++ XFTdebug("XftFontMatch error");
+ FcPatternDestroy( request);
+ return false;
+ }
++ /* if (pguts->debug & DEBUG_FONTS) { FcPatternPrint(match); } */
+ FcPatternDestroy( request);
+
+ /* xft does a rather bad job with synthesizing a monospaced
+ font out of a proportional one ... try to find one ourself,
+ or bail out if it is the case
+ */
+- if ( f.pitch == fpFixed && !force_xft_monospace_emulation) {
++ if ( requested_font.pitch == fpFixed && !force_xft_monospace_emulation) {
+ int spacing = -1;
+
+ if (
+@@ -662,7 +731,7 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ ) {
+ Font font_with_family;
+ char * monospace_font;
+- font_with_family = f;
++ font_with_family = requested_font;
+ fcpattern2fontnames(match, &font_with_family);
+ FcPatternDestroy( match);
+
+@@ -670,18 +739,18 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ /* try a good mono font, again */
+ Font s = *source;
+ strcpy(s.name, monospace_font);
+- Fdebug("xft: try fixed pitch\n");
+- return prima_xft_font_pick( self, &s, dest, size);
++ XFTdebug("try fixed pitch");
++ return prima_xft_font_pick( self, &s, dest, size, xft_result);
+ } else {
+ Bool ret;
+- Fdebug("xft: force ugly monospace\n");
++ XFTdebug("force ugly monospace");
+ force_xft_monospace_emulation++;
+- ret = prima_xft_font_pick( self, source, dest, size);
++ ret = prima_xft_font_pick( self, source, dest, size, xft_result);
+ force_xft_monospace_emulation--;
+ return ret;
+ }
+ }
+- } else if ( f.pitch == fpVariable ) {
++ } else if ( requested_font.pitch == fpVariable ) {
+ /*
+ xft picks a monospaced font when a proportional one is requested if the name points at it.
+ Not that this is wrong, but in Prima terms pich is heavier than name (this concept was borrowed from win32).
+@@ -696,18 +765,18 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ ) {
+ Font font_with_family;
+ char * proportional_font;
+- font_with_family = f;
++ font_with_family = requested_font;
+ fcpattern2fontnames(match, &font_with_family);
+
+ if (( proportional_font = find_good_font_by_family(&font_with_family, FC_PROPORTIONAL))) {
+ /* try a good variable font, again */
+ Font s = *source;
+ strcpy(s.name, proportional_font);
+- Fdebug("xft: try variable pitch\n");
++ XFTdebug("try variable pitch");
+ FcPatternDestroy( match);
+- return prima_xft_font_pick( self, &s, dest, size);
++ return prima_xft_font_pick( self, &s, dest, size, xft_result);
+ } else {
+- Fdebug("xft: variable pitch is not found within family %s\n", font_with_family.family);
++ XFTdebug("variable pitch is not found within family %s", font_with_family.family);
+ }
+ }
+
+@@ -722,15 +791,15 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ ( FcCharSetCount(c) == 0) ||
+
+ (
+- f. encoding[0] &&
+- ( strcmp( f. encoding, fontspecific) != 0) &&
++ requested_font. encoding[0] &&
++ ( strcmp( requested_font. encoding, fontspecific) != 0) &&
+ ( FcCharSetIntersectCount( csi-> fcs, c) < csi-> glyphs - 1)
+ )
+ )) {
+- xft_build_font_key( &key, &f, by_size);
++ xft_build_font_key( &key, &requested_font, by_size);
+ key. width = 0;
+ hash_store( mismatch, &key, sizeof( FontKey), (void*)1);
+- Fdebug("xft: charset mismatch\n");
++ XFTdebug("charset mismatch (%s)", requested_font. encoding);
+ FcPatternDestroy( match);
+ return false;
+ }
+@@ -741,10 +810,10 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ {
+ FcBool scalable;
+ if (( FcPatternGetBool( match, FC_SCALABLE, 0, &scalable) == FcResultMatch) && !scalable) {
+- xft_build_font_key( &key, &f, by_size);
++ xft_build_font_key( &key, &requested_font, by_size);
+ key. width = 0;
+ hash_store( mismatch, &key, sizeof( FontKey), (void*)1);
+- Fdebug("xft: refuse bitmapped font\n");
++ XFTdebug("refuse bitmapped font");
+ FcPatternDestroy( match);
+ return false;
+ }
+@@ -753,14 +822,14 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ /* XXX copy font details - very important these are correct !!! */
+ /* strangely enough, if the match is used after XftFontOpenPattern, it is
+ destroyed */
+- f1 = f;
++ loaded_font = requested_font;
+ if ( !kf_base) {
+- Bool underlined = f1. style & fsUnderlined;
+- Bool strike_out = f1. style & fsStruckOut;
+- fcpattern2font( match, &f1);
+- if ( f. width > 0) f1. width = f. width;
+- if ( underlined) f1. style |= fsUnderlined;
+- if ( strike_out) f1. style |= fsStruckOut;
++ Bool underlined = loaded_font. style & fsUnderlined;
++ Bool strike_out = loaded_font. style & fsStruckOut;
++ fcpattern2font( match, &loaded_font);
++ if ( requested_font. width > 0) loaded_font. width = requested_font. width;
++ if ( underlined) loaded_font. style |= fsUnderlined;
++ if ( strike_out) loaded_font. style |= fsStruckOut;
+ }
+
+
+@@ -768,14 +837,14 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ {
+ FcChar8 * s = nil;
+ FcPatternGetString( match, FC_FAMILY, 0, &s);
+- if ( !s || strcmp(( const char*) s, f. name) != 0) {
++ if ( !s || strcmp(( const char*) s, requested_font. name) != 0) {
+ int i, n = guts. n_fonts;
+ PFontInfo info = guts. font_info;
+
+ if ( !guts. xft_priority) {
+- Fdebug("xft: name mismatch\n");
++ XFTdebug("name mismatch");
+ NAME_MISMATCH:
+- xft_build_font_key( &key, &f, by_size);
++ xft_build_font_key( &key, &requested_font, by_size);
+ key. width = 0;
+ hash_store( mismatch, &key, sizeof( FontKey), (void*)1);
+ FcPatternDestroy( match);
+@@ -783,8 +852,8 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ }
+
+ /* check if core has cached face name */
+- if ( prima_find_known_font( &f, false, by_size)) {
+- Fdebug("xft: pass to cached core\n");
++ if ( prima_find_known_font( &requested_font, false, by_size)) {
++ XFTdebug("pass to cached core");
+ goto NAME_MISMATCH;
+ }
+
+@@ -793,9 +862,9 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ if (
+ info[i]. flags. disabled ||
+ !info[i].flags.name ||
+- (strcmp( info[i].font.name, f.name) != 0)
++ (strcmp( info[i].font.name, requested_font.name) != 0)
+ ) continue;
+- Fdebug("xft: pass to core\n");
++ XFTdebug("pass to core");
+ goto NAME_MISMATCH;
+ }
+ }
+@@ -804,91 +873,81 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ /* load the font */
+ xf = XftFontOpenPattern( DISP, match);
+ if ( !xf) {
+- xft_build_font_key( &key, &f, by_size);
++ xft_build_font_key( &key, &requested_font, by_size);
+ key. width = 0;
+ hash_store( mismatch, &key, sizeof( FontKey), (void*)1);
+- Fdebug("xft: XftFontOpenPattern error\n");
++ XFTdebug("XftFontOpenPattern error");
+ FcPatternDestroy( match);
+ return false;
+ }
++ XFTdebug("load font %x", xf);
++
+ if ( kf_base) {
+ /* A bit hacky, since the rotated font may be substituted by Xft.
+ We skip the non-scalable fonts earlier to assure this doesn't happen,
+ but anyway it's not 100% */
+- Bool underlined = f1. style & fsUnderlined;
+- Bool strike_out = f1. style & fsStruckOut;
+- f1 = kf_base-> font;
+- f1. direction = f. direction;
+- strcpy( f1. encoding, csi-> name);
+- if ( underlined) f1. style |= fsUnderlined;
+- if ( strike_out) f1. style |= fsStruckOut;
++ Bool underlined = loaded_font. style & fsUnderlined;
++ Bool strike_out = loaded_font. style & fsStruckOut;
++ loaded_font = kf_base-> font;
++ loaded_font. direction = requested_font. direction;
++ strcpy( loaded_font. encoding, csi-> name);
++ if ( underlined) loaded_font. style |= fsUnderlined;
++ if ( strike_out) loaded_font. style |= fsStruckOut;
+ } else {
+- f1. internalLeading = xf-> height - f1. size * guts. resolution. y / 72.27 + 0.5;
++ loaded_font. internalLeading = xf-> height - loaded_font. size * guts. resolution. y / 72.27 + 0.5;
+ if ( !by_size && !exact_pixel_size) {
+ /* Try to locate the corresponding size and
+- height; multiply size by 10 to address pixel-wise heights correctly.
+- The max. screen resolution allowable here is therefore 720 dpi.
+- Experiments show that factors more than 10 are bad, since too
+- precise arguments befuddle the heights guesser, as heights are still
+- integers. Initially I thought that it was the Prima flaw that it doesn't
+- provide size precision less than 1.0, but it is not so - Xft's
+- xf->height and fc's FC_PIXEL_SIZE are way different, and this
+- cannot be compensated, except by guess. */
++ the correct height - FC_PIXEL_SIZE is not correct most probably
++ multiply size by 10 to address pixel-wise heights correctly.
++ */
+ HeightGuessStack hgs;
+- PCachedFont ksz = nil;
+- int h, sz = f1. size * 10, last_sz = -1;
+-
+- ksz = try_size( self, f1, ( double) sz / 10.0);
+- if ( ksz) {
+- h = ksz-> font. height;
+- Fdebug("xft-match:init:%d, %d => %d\n", f1.height, sz, h);
+- if ( h != f1. height) {
+- prima_init_try_height( &hgs, f1. height, sz);
++ int h, sz, last_sz = -1;
++ XftFont * guessed_font = nil;
++
++ sz = 10.0 * (float) loaded_font. size * (float) loaded_font. height / (float) xf->height;
++ XFTdebug("need to figure the corresponding size - try %g first...", ( double) sz / 10.0);
++ guessed_font = try_size( self, loaded_font, ( double) sz / 10.0);
++
++ if ( guessed_font) {
++ h = guessed_font-> height;
++ XFTdebug("got height = %d", h);
++ if ( h != requested_font. height) {
++ XFTdebug("not good enough, try approximation from size %g", ( double) sz / 10.0);
++ prima_init_try_height( &hgs, requested_font. height, sz);
+ while ( 1) {
+ last_sz = sz;
+ sz = prima_try_height( &hgs, h);
+ if ( sz < 0) break;
+- ksz = try_size( self, f1, ( double) sz / 10.0);
+- if ( !ksz) break;
+- h = ksz-> font. height;
+- Fdebug("%d => %d\n", sz, h);
+- if ( h == f1. height) break;
++ guessed_font = try_size( self, loaded_font, ( double) sz / 10.0);
++ if ( !guessed_font) break;
++ h = guessed_font-> height;
++ XFTdebug("size %.1f got us %d pixels", ( float) sz / 10.0, h);
++ if ( h == 0 || h == requested_font. height) break;
+ }
+ }
+ if ( sz < 0) sz = last_sz;
+- Fdebug("fini:%d\n", sz);
+- if ( sz > 0) f1. size = (double) sz / 10.0 + 0.5;
+- }
+-
+- if ( ksz && f1. height != xf-> height) {
+- /* the height returned is invalid, but cache it anyway */
+- xft_build_font_key( &key, &f1, false);
+- if ( !hash_fetch( guts. font_hash, &key, sizeof(FontKey))) {
+- if (( kf = malloc( sizeof( CachedFont)))) {
+- bzero( kf, sizeof( CachedFont));
+- memcpy( &kf-> font, &f1, sizeof( Font));
+- kf-> font. style &= ~(fsUnderlined|fsOutline|fsStruckOut);
+- kf-> xft = kf-> xft_base = xf;
+- hash_store( guts. font_hash, &key, sizeof( FontKey), kf);
+- Fdebug("xft:store %x:%d.%d.%d.%d.%s\n", kf->xft, key.height, key. width, key.style, key.pitch, key.name);
+- }
+- }
++ if ( sz > 0) {
++ loaded_font. size = (double) sz / 10.0 + 0.5;
++ XFTdebug("found size: %.1f (%d)", ( float) sz / 10.0, loaded_font. size);
++ }
++ } else {
++ XFTdebug("found nothing");
++ }
+
+- /* and, finally, replace the font and compute internal leading */
+- xf = ksz-> xft;
+- f1. height = xf-> height;
+- f1. internalLeading = xf-> height - f1. size * guts. resolution. y / 72.27 + 0.5;
++ if ( guessed_font && requested_font. height != xf-> height) {
++ xf = guessed_font;
++ loaded_font. height = xf-> height;
++ XFTdebug("redirect to font %x", xf);
+ }
+- Fdebug("xft:sz:%d, h:%d\n", f1.size, f1.height);
+- } else
+- f1. height = xf-> height;
++ XFTdebug("guessed size %d", loaded_font.size);
++ } else {
++ loaded_font. height = xf-> height;
++ XFTdebug("set height: %d", loaded_font.height);
++ }
+
+- f1. ascent = xf-> ascent;
+- f1. descent = xf-> descent;
+-
+- f1. maximalWidth = xf-> max_advance_width;
++ loaded_font. maximalWidth = xf-> max_advance_width;
+ /* calculate average font width */
+- if ( f1. pitch != fpFixed) {
++ if ( loaded_font. pitch != fpFixed) {
+ FcChar32 c;
+ XftFont *x = kf_base ? kf_base-> xft : xf;
+ int num = 0, sum = 0;
+@@ -900,42 +959,24 @@ prima_xft_font_pick( Handle self, Font * source, Font * dest, double * size)
+ sum += glyph. xOff;
+ num++;
+ }
+- f1. width = ( num > 10) ? (sum / num) : f1. maximalWidth;
++ loaded_font. width = ( num > 10) ? (sum / num) : loaded_font. maximalWidth;
+ } else
+- f1. width = f1. maximalWidth;
++ loaded_font. width = loaded_font. maximalWidth;
+ }
+
+- /* create hash entry for subsequent loads of same font */
+- xft_build_font_key( &key, &f, by_size);
+- if ( !hash_fetch( guts. font_hash, &key, sizeof(FontKey))) {
+- if (( kf = malloc( sizeof( CachedFont)))) {
+- bzero( kf, sizeof( CachedFont));
+- memcpy( &kf-> font, &f1, sizeof( Font));
+- kf-> font. style &= ~(fsUnderlined|fsOutline|fsStruckOut);
+- kf-> xft = xf;
+- kf-> xft_base = kf_base ? kf_base-> xft : xf;
+- hash_store( guts. font_hash, &key, sizeof( FontKey), kf);
+- Fdebug("xft:store %x:%d.%d.%d.%d.%s\n", kf->xft, key.height, key. width, key.style, key.pitch, key.name);
+- }
+- }
++ loaded_font. descent = xf-> descent;
++ loaded_font. ascent = xf-> ascent;
+
+- /* and with the matched by height and size */
+- for ( i = 0; i < 2; i++) {
+- xft_build_font_key( &key, &f1, i);
+- if ( !hash_fetch( guts. font_hash, &key, sizeof(FontKey))) {
+- if (( kf = malloc( sizeof( CachedFont)))) {
+- bzero( kf, sizeof( CachedFont));
+- memcpy( &kf-> font, &f1, sizeof( Font));
+- kf-> font. style &= ~(fsUnderlined|fsOutline|fsStruckOut);
+- kf-> xft = xf;
+- kf-> xft_base = kf_base ? kf_base-> xft : xf;
+- hash_store( guts. font_hash, &key, sizeof( FontKey), kf);
+- Fdebug("xft:store %x:%d.%d.%d.%d.%s\n", kf->xft, key.height, key. width, key.style, key.pitch, key.name);
+- }
+- }
++ if ( cache_results ) {
++ /* create hash entry for subsequent loads of same font */
++ xft_store_font(&requested_font, &loaded_font, by_size, xf, kf_base ? kf_base-> xft : xf);
++ /* and with the matched by height and size */
++ for ( i = 0; i < 2; i++)
++ xft_store_font(&loaded_font, &loaded_font, i, xf, kf_base ? kf_base-> xft : xf);
+ }
+
+- *dest = f1;
++ *dest = loaded_font;
++ if ( xft_result ) *xft_result = xf;
+ return true;
+ }
+
+@@ -1669,9 +1710,9 @@ prima_xft_parse( char * ppFontNameSize, Font * font)
+ }
+ }
+ FcPatternDestroy( p);
+- if ( !prima_xft_font_pick( nilHandle, &f, &def, nil)) return false;
++ if ( !prima_xft_font_pick( nilHandle, &f, &def, nil, nil)) return false;
+ *font = def;
+- Fdebug( "parsed ok: %d.%s\n", def.size, def.name);
++ XFTdebug( "parsed ok: %d.%s", def.size, def.name);
+ return true;
+ }
+
+--
+2.4.3
+
diff --git a/perl-Prima.spec b/perl-Prima.spec
index deb50dd..eb1c7bc 100644
--- a/perl-Prima.spec
+++ b/perl-Prima.spec
@@ -2,12 +2,14 @@
Name: perl-Prima
Version: 1.42
-Release: 2%{?dist}
+Release: 3%{?dist}
Summary: Perl graphic toolkit
License: BSD
Group: Development/Libraries
URL: http://search.cpan.org/dist/Prima/
Source0: http://www.cpan.org/authors/id/K/KA/KARASIK/Prima-%{version}.tar.gz
+# Fix XFT font handling, bug #1275092
+Patch0: Prima-1.42-rehaul-of-xft-for-testing-of-corner-cases.patch
BuildRequires: fontconfig-devel
BuildRequires: freetype-devel
BuildRequires: giflib-devel
@@ -84,6 +86,7 @@ Prima-related code together with standard Perl Test:: suite.
%prep
%setup -q -n Prima-%{version}
+%patch0 -p1
%build
perl Makefile.PL INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" WITH_GTK2=1
@@ -119,6 +122,9 @@ find $RPM_BUILD_ROOT -type f -name '*.bs' -size 0 -exec rm -f {} \;
%{_mandir}/man3/Prima::Test.*
%changelog
+* Tue Oct 27 2015 Petr Pisar <ppisar at redhat.com> - 1.42-3
+- Fix XFT font handling (bug #1275092)
+
* Mon Mar 16 2015 Petr Pisar <ppisar at redhat.com> - 1.42-2
- Provide perl(Prima::noX11)
--
cgit v0.11.2
http://pkgs.fedoraproject.org/cgit/perl-Prima.git/commit/?h=f22&id=c284b74408ab2c40ef2140684398f49f5ad7fc8a
More information about the perl-devel
mailing list