wall_john 发表于 2005-9-11 19:51:46

关于字体问题和fcitx的补丁

关于字体问题和fcitx的补丁

1、MagicLinux中字体出现的问题
最近发现MagicLinux中宋体从9号字到12号字字体大小都一样,全部使用的12号字体。
查了查原因,发现在配置文件:
/etc/fonts/conf.d/20glc-default.conf(注意是utf8编码的文件)
做了如下配置:
<match target="font" >
          <test name="family" qual="any" >
                <string>宋体</string>
                <string>新宋体</string>
                <string>SimSun</string>
                <string>NSimSun</string>
                <string>宋体-18030</string>
                <string>新宋体-18030</string>
                <string>SimSun-18030</string>
                <string>NSimSun-18030</string>
                <string>文鼎 PL 新宋</string>
                <string>AR PL New Sung</string>
          </test>
          <test compare="more_eq" name="pixelsize" >
                <int>9</int>
          </test>
          <test compare="less_eq" name="pixelsize" >
                <int>12</int>
          </test>
          <edit mode="assign" name="pixelsize" >
                <int>12</int>
          </edit>
</match>

就是说:字体大小(像素)从9-12都使用大小为12的字体,原来如此:)

顺便说一下,以前大家经常问的新宋体字符之间间隔过大的问题也是在该文件中解决的,
在文件中:
<!--
          Add by Firefly([email protected])
          Most of Asian fonts can't explain by freetype2,
          so,if these fonts have dual width(half/full) and monospacing,
          you need to disable globaladvance.
-->
<match target="font" >
        <test compare="more_eq" name="spacing" >
          <const>dual</const>
        </test>
        <edit mode="assign" name="globaladvance" >
          <bool>false</bool>
        </edit>
</match>
上面firefly老兄的解释说的很清楚了。

这个文件被fontconfig的配置文件/etc/fonts/fonts.conf调用,fonts.conf中如下:
<!--
Load local system customization file
-->
        <include ignore_missing="yes">conf.d</include>
即/etc/fonts/conf.d目录下的配置文件将读入到主配置,如果存在的话。


2、宋体9-12都使用12号字的原因
如果不这样则qt和gtk程序显示的字体不一致,qt中对字体按屏幕的大小做了到字体大小
的转换。
在代码QTSRC/src/kernel/qfontdatabase_x11.cpp函数addPatternProps中:

size_value = size_value*72./QPaintDevice::x11AppDpiY(fp->screen)

QPaintDevice::x11AppDpiY是取某个屏幕的像素,屏幕像素的构建在qt源代码
QTSRC/src/kernel/qpaintdevice_x11.cpp函数create_dpis中,将这几个函数接合起来,
大致字体大小转换如下:

double GetFontSize(Display * dpy, int iScreen, int size)
{
    double font_size = size; /*传入的字体大小*/
    int i = iScreen;         /*当前屏幕*//
    /*int dpisX = (DisplayWidth(dpy,i) * 254 + DisplayWidthMM(dpy,i)*5)
                / (DisplayWidthMM(dpy,i)*10);*/ /*用xlib中的宏取屏幕X轴像素,这里没用到*/
    int dpisY = (DisplayHeight(dpy,i) * 254 + DisplayHeightMM(dpy,i)*5)
                / (DisplayHeightMM(dpy,i)*10);/*用xlib中的宏取屏幕Y轴像素*/
    font_size = font_size * 72. / dpisY;      /*转换为pixel大小*/
    return font_size;
}

而gtk的程序估计是没这样转换的(手上没有pango的最新源代码:),如果这样转换了
字体就能和这个一样了,我用fcitx的代码测试过,fcitx中也使用XFT这组font的处理函
数,修改之后和qt的程序显示字体大小一致(当然是将20glc-default.conf中的那个控制
关掉之后,否则不论你改不改都将一致),附件中有个fcitx的补丁。

wall_john 发表于 2005-9-16 19:44:22

不好意思,我发现上面的说法有问题
概念:
DPI dots per inch 每英寸点数
inch 英寸 2.54cm
pixel 像素 72dots

公式:
a.从字体大小到像素大小公式
pixel_size = size * DPI / 72.0
b.从像素大小到字体大小公式
size = pixel_size * 72.0 / DPI
c.字体显示的实际大小公式
size * DPI / 72.0 / 屏幕横向分辨率 * 显示器横向长度
例如
9号字 15寸屏幕 1024x768分辨率
9 * 96 / 72 / 1024 * 15 * 2.54 ~= 0.446cm ~= 4.5mm
这实际得到的近似于字体的长度
d.不同dpi之间的字体大小
new_size = old_size * OLD_DPI / NEW_DPI

为什么在DPI为75时,qt程序字体与gtk的字体不一致?可能因为qt中当DPI为75时使pixelsize
和字体size设置成一样的,看看下面这个两个函数qt-copy-20050419/src/kernel/qfont_x11.cpp:
double qt_pixelSize(double pointSize, QPaintDevice *paintdevice, int scr)
{
    if (pointSize < 0) return -1.;

    double result = pointSize;
    if (paintdevice && QPaintDeviceMetrics( paintdevice ).logicalDpiY() != 75) // 当dpi!=75才
      result *= QPaintDeviceMetrics( paintdevice ).logicalDpiY() / 72.;
    else if (QPaintDevice::x11AppDpiY( scr ) != 75)                            // 当dpi!=75才
      result *= QPaintDevice::x11AppDpiY( scr ) / 72.;

    return result;
}

double qt_pointSize(double pixelSize, QPaintDevice *paintdevice, int scr)
{
    if (pixelSize < 0) return -1.;

    double result = pixelSize;
    if ( paintdevice && QPaintDeviceMetrics( paintdevice ).logicalDpiY() != 75) // 当dpi!=75才
      result *= 72. / QPaintDeviceMetrics( paintdevice ).logicalDpiY();
    else if (QPaintDevice::x11AppDpiY(scr) != 75)                               // 当dpi!=75才
      result *= 72. / QPaintDevice::x11AppDpiY( scr );

    return result;
}
当dpi为75时pointsize==pixelsize,gtk的程序没有这样pango-1.8.1/pango/pangofc-fontmap.c:
static FcPattern *
pango_fc_make_pattern (const PangoFontDescription *description)
{
    FcPattern *pattern;
    int slant;
    int weight;
    double size;
    gboolean size_is_absolute;
    char **families;
    int i;
#ifdef FC_WIDTH
    int width;
#endif

    slant = pango_fc_convert_slant_to_fc (pango_font_description_get_style (description));
    weight = pango_fc_convert_weight_to_fc (pango_font_description_get_weight (description));
#ifdef FC_WIDTH
    width = pango_fc_convert_width_to_fc (pango_font_description_get_stretch (description));
#endif

    size = (double) pango_font_description_get_size (description) / PANGO_SCALE;
    size_is_absolute = pango_font_description_get_size_is_absolute (description);

    pattern = FcPatternBuild (NULL,
                  FC_WEIGHT, FcTypeInteger, weight,
                  FC_SLANT,FcTypeInteger, slant,
#ifdef FC_WIDTH
                  FC_WIDTH,FcTypeInteger, width,
#endif          // 看看下面这里
                  (size_is_absolute ? FC_PIXEL_SIZE : FC_SIZE),FcTypeDouble,size,
                  NULL);

    families = g_strsplit (pango_font_description_get_family (description), ",", -1);

    for (i = 0; families; i++)
      FcPatternAddString (pattern, FC_FAMILY, families);

    g_strfreev (families);

    return pattern;
}
前面的fcitx补丁就是无论在任何的DPI下可以使字体大小总是等于像素大小,所以只要分辨率不变字体
显示的实际大小就不会变。

wall_john 发表于 2005-9-16 19:46:43

上述情况描述的是当/usr/X11R6/bin/X默认启动的情况,而不是在像magiclinux加-dpi 96
的时候,默认启动的时候X的DPI实际为75,而非96。
上面那个选项的设置如果是kdm登陆的话在配置文件/usr/share/config/kdm/kdmrc中:
ServerCmd=/usr/X11R6/bin/X -dpi 96
如果是startx启动的话在~/.xserverrc 或 /etc/X11/xinit/xserverrc中,如果不存在则
默认用X:0启动,中间还有调用xinitrc启动相应桌面的过程这里忽略了。
奇怪的是,即算不加-dpi 96显示的字体还是会与DPI为96的时候一致,分析了一下原因,X
配置文件中有几项与字体配置相关选项:
# xrdb -query | grep -i xft
Xft.dpi:      96
Xft.antialias:0
Xft.hinting:    1
Xft.hintstyle:hintmedium

Xft.dpi就是字体英尺像素的开关,所以不管X怎么启动,字体的大小都为96像素每英尺计算。
这个配置文件在/usr/share/config/kdm/Xresources和/etc/X11/Xresources中,是通过X
资源装载程序xrdb装载的。

所以有很多linux程序默认字体大小为12而不是9号字,比如qt程序中QTSRC/src/kernel/qfont.h:
QFont( const QString &family, int pointSize = 12, int weight = Normal,
         bool italic = FALSE );

fontconfig的源代码中fontconfig-2.3.2/src/fcdefault.c:
void
FcDefaultSubstitute (FcPattern *pattern)
....
if (FcPatternGet (pattern, FC_PIXEL_SIZE, 0, &v) == FcResultNoMatch)
    {
      doubledpi, size, scale;
                /* 如果未设置字体大小默认用12号字 */
      if (FcPatternGetDouble (pattern, FC_SIZE, 0, &size) != FcResultMatch)
      {
            size = 12.0;
            (void) FcPatternDel (pattern, FC_SIZE);
            FcPatternAddDouble (pattern, FC_SIZE, size);
      }
      if (FcPatternGetDouble (pattern, FC_SCALE, 0, &scale) != FcResultMatch)
      {
            scale = 1.0;
            (void) FcPatternDel (pattern, FC_SCALE);
            FcPatternAddDouble (pattern, FC_SCALE, scale);
      }
      size *= scale;
                /* 如果未设置DPI默认用75(这与X后台默认值对应) */
      if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) != FcResultMatch)
      {
            dpi = 75.0;
            (void) FcPatternDel (pattern, FC_DPI);
            FcPatternAddDouble (pattern, FC_DPI, dpi);
      }
      size *= dpi / 72.0; /* 字体大小到实际PIXEL大小,是上面公式的反算 */
      FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
    }
....
实际上,在X启动时加-dpi 96并不是很好的方法与X标准设置不一致,也与许多程序代码
内部操作不吻合。现在很多其他的发行版本并没有这样做比如fedora字体标准大小就是
12号字,但是从magiclinux的实际情况来看好像还不错:)。

tingxx 发表于 2005-9-17 12:40:27

虽然我不懂,但感觉是个好贴:)

楼上的继续努力,为广大fans造福呀 :wink:
页: [1]
查看完整版本: 关于字体问题和fcitx的补丁