Ticket UUID: | 434d294df8b053246ee86e7898d06bc3a6d1d771 | |||
Title: | fix type mismatch in unix/tkUnixRFont.c | |||
Type: | Patch | Version: | 8.6 | |
Submitter: | yorwba | Created on: | 2017-02-22 08:45:46 | |
Subsystem: | 46. Unix Fonts | Assigned To: | jan.nijtmans | |
Priority: | 5 Medium | Severity: | Critical | |
Status: | Closed | Last Modified: | 2017-07-03 07:46:39 | |
Resolution: | Fixed | Closed By: | jan.nijtmans | |
Closed on: | 2017-07-03 07:46:39 | |||
Description: |
The code in unix/tkUnixRFont.c uses XftPattern{Get,Add}Integer to manipulate the XFT_PIXEL_SIZE property. This is incorrect, since fontconfig expects it to be a double (see the comment on https://cgit.freedesktop.org/fontconfig/tree/fontconfig/fontconfig.h#n83 Line 83, XFT_PIXEL_SIZE is an alias for FC_PIXEL_SIZE). This bug leads to incorrect reporting of font sizes in some cases, e.g. the test case "font-44.1 TkFontGetPixels: size < 0" fails with output 0 on my machine. For context: that test case is tk scaling 0.5 font actual {times -12} -size and expected output is 24. After changing the code to call XftPattern{Get,Add}Double instead, the test case still fails, but outputs 9 instead. I believe this is related to [tk scaling] being ignored and 9 being the number of points in 12 pixels on my display. Patch: --- tkUnixRFont.c +++ tkUnixRFont.c @@ -170,16 +170,16 @@ { const char *family = "Unknown"; const char *const *familyPtr = &family; - int weight, slant, size, pxsize; - double ptsize; + int weight, slant, size; + double ptsize, pxsize; (void) XftPatternGetString(ftFont->pattern, XFT_FAMILY, 0, familyPtr); if (XftPatternGetDouble(ftFont->pattern, XFT_SIZE, 0, &ptsize) == XftResultMatch) { size = (int) ptsize; - } else if (XftPatternGetInteger(ftFont->pattern, XFT_PIXEL_SIZE, 0, + } else if (XftPatternGetDouble(ftFont->pattern, XFT_PIXEL_SIZE, 0, &pxsize) == XftResultMatch) { - size = -pxsize; + size = -(int) pxsize; } else { size = 12; } @@ -444,7 +444,7 @@ if (faPtr->size > 0) { XftPatternAddDouble(pattern, XFT_SIZE, (double)faPtr->size); } else if (faPtr->size < 0) { - XftPatternAddInteger(pattern, XFT_PIXEL_SIZE, -faPtr->size); + XftPatternAddDouble(pattern, XFT_PIXEL_SIZE, -(double)faPtr->size); } else { XftPatternAddDouble(pattern, XFT_SIZE, 12.0); } | |||
User Comments: |
jan.nijtmans added on 2017-07-03 07:46:39:
Thanks, François, for reminding me. Yes, I think everything is handled now. Closing. fvogel added on 2017-07-02 19:46:45: You didn't report here, Jan, but I believe you took Christian's comment into account in [9ab129aa0d372250]. Can we close this bug then? Or what is it that should still be done? chw added on 2017-05-20 03:08:04: Check-in [6c1859a0] has the wrong logic in dealing with XLFD_PIXEL_SIZE, see https://www.androwish.org/index.html/artifact?name=5cef6e6b3903ef42&ln=4003-4008 for a fix. jan.nijtmans added on 2017-05-19 13:51:34: I'm confident that this bug is now fixed in core-8-6-branch. Tested on Ubuntu, where there indeed were some fonts which returned 0 for "font actial -size", after this fix the font size returns 9. Please confirm, then I'll close this issue. gcramer added on 2017-05-16 16:50:09: > bug-434d294df with --enable-xft: [font actual $x -size] always gives 9.0. This might be an issue, for compatibility reasons it may return "9", and the user normally specifies "size 9", and not -size "9.0". aspect added on 2017-05-16 14:08:47: I don't really follow what's going on here, but an observation from Fedora 24: Xft seems to play a role. trunk with --enable-xft: [font actual $x -size] always gives 0. bug-434d294df with --enable-xft: [font actual $x -size] always gives 9.0. trunk with --disable-xft looks more reasonable: % pack req Tk 8.7a0 % font actual TkFixedFont -family courier -size 9 -weight normal -slant roman -underline 0 -overstrike 0 % font actual {times -12} -size 9 % tk scaling 1.3333333333333333 % tk scaling 0.5 % font actual {times -12} -size 24 bug-434d294df with --disable-xft: % pack req Tk 8.7a0 % font actual TkFixedFont -family courier -size 9.0 -weight normal -slant roman -underline 0 -overstrike 0 % font actual {times -12} -size 9.0 % tk scaling 1.3333333333333333 % tk scaling 0.5 % font actual {times -12} -size 24.005905511811026 dkf added on 2017-05-15 12:25:00:
Is there a particular reason for not using fvogel added on 2017-03-26 12:39:41: Aside from Gregor's remark, which looks sensible, the bugfix branch does not compile for me on Vista due to: tkWinDialog.c C:\Users\francois\Documents\Development\tcltk-fossil\tk\win\..\win\tkWinDialog.c(3454) : error C2220: warning treated as error - no 'object' file generated C:\Users\francois\Documents\Development\tcltk-fossil\tk\win\..\win\tkWinDialog.c(3454) : warning C4244: 'function' : conversion from 'double' to 'int', possible loss of data I didn't dive into the details of the problem and of the proposed fix, and have no plans to do so, at least in the immediate future due to lack of time... gcramer added on 2017-03-22 14:09:11: I've stumbled over this (changed) line in TkFontGetPixels.c [f9348cf1]: 1231: fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10;So far as I see fontPtr->underlineHeight is still an integer type. Now TkFontGetPixels() returns an un-rounded double. This means that the value TkFontGetPixels()/10 now has the tendency to become smaller, example: (int)(19.9/10) = 1 // new computation ((int)(19.9 + 0.5))/10 = 2 // old computationbecause in old implementation TkFontGetPixels() has returned the rounded value (int)(19.9 + 0.5). So this change will in general produce underlines with less height. I'm not sure that this is intended. (But probably I have overseen anything else.) jan.nijtmans added on 2017-03-21 14:34:21: Reading the documentation on XFT_PIXEL_SIZE, indeed this is expected to be a double not an integer. Suggested fix in [f9348cf17680c53049245ed7510677ce2faefb3e|f9348cf176]. Test-cases not adapted yet. Since this change means that in more places double's are used in stead of integers, not sure this should be done for Tk <= 8.6. François, how is your feeling on this, since you are deeper in Tk than I am? Please review. yorwba added on 2017-02-24 06:37:31: Apparently the conversion from point size to pixel size was introduced in commit 3cd573fc of fontconfig, which is identified as Version 2.11.1, 2014-03-24 in the corresponding README. I have > apt-cache policy libfontconfig1 | grep Installed Installed: 2.11.94-0ubuntu1.1 Since your Mint system is based on Ubuntu 14.04, the change is probably not included in your version of fontconfig. bll added on 2017-02-23 18:04:37: My system always returns -12 for the font size, whether the display size is configured in X11.conf or not. bll added on 2017-02-23 17:57:06: Some notes: test 44.1 as written assumes that the point size will be returned. On my system, where the display size is configured (and thus tk scaling is ignored), the code returns the pixel size (and therefore test 44.1 is incorrect). # linux mint 17.3 (ubuntu 14.04) % font actual {{Nimbus Roman No9 L} -12} -size # patched code -12 On a pristine ubuntu 16.10, the font size is returned in points (where the display size is not configured). # ubuntu 16.10 % font actual {{Nimbus Roman No9 L} -12} -size # patched code 9 The unpatched 8.6.6 that comes with ubuntu 16.10 always returns a size of 0. I don't know if the font size reporting difference is due to changes in X11, the display size being configured, the font configuration or something else. I will turn off my display size config and retest. bll added on 2017-02-23 16:37:34: The conversions of ...GetInteger are not necessary. The change at line 447 is correct. New patch attached. 00051 Bool 00062 XftPatternAddInteger (XftPattern *p, const char *object, int i) 00063 { 00064 XftValue v; 00065 00066 v.type = XftTypeInteger; 00067 v.u.i = i; 00068 return XftPatternAdd (p, object, v, True); 00069 } 00119 XftResult 00120 XftPatternGetInteger (XftPattern *p, const char *object, int id, int *i) 00121 { 00122 XftValue v; 00123 XftResult r; 00124 00125 r = XftPatternGet (p, object, id, &v); 00126 if (r != XftResultMatch) 00127 return r; 00128 switch (v.type) { 00129 case XftTypeDouble: 00130 *i = (int) v.u.d; 00131 break; 00132 case XftTypeInteger: 00133 *i = v.u.i; 00134 break; 00135 default: 00136 return XftResultTypeMismatch; 00137 } 00138 return XftResultMatch; 00139 } yorwba added on 2017-02-23 07:55:48: I noticed the bug using Tkinter from Python, but then grabbed the Tk 8.6.6 tarball to reproduce. Output of unpatched wish: % font actual {times -12} -family {TeX Gyre Termes} -size 0 -weight normal -slant roman -underline 0 -overstrike 0 Patched: % font actual {times -12} -family {TeX Gyre Termes} -size 9 -weight normal -slant roman -underline 0 -overstrike 0 While multiple functions of the XftPattern* interface can be used, each property must be set with the correct type. If you look at the table under https://keithp.com/~keithp/talks/xtc2001/paper/xft.html#sec-xft-name you can see that both size and pixelsize are supposed to be doubles. Xft (actually fontconfig) doesn't do any type conversions at the boundary when you try to set the pixel size to the integer value 12. Instead an integer-valued union field is set and when fontconfig converts the pixel size into the point size, it reads the double field, which has value 5.9287877500949585e-323. During conversion this value underflows, yielding a point size of 0. bll added on 2017-02-22 16:24:25: What is the output of [font actual {times -12}] on your machine? What version of Tk are you using? There are various different XftPattern* interfaces that can be used. References: https://keithp.com/~keithp/talks/xtc2001/paper/ |
Attachments:
- font.diff [download] added by bll on 2017-02-23 16:39:13. [details]