初识shell
2016-01-19 18:10
501 查看
现在Java的字体渲染比以前进步多了,但最近装了个Monaco,却发现无论如何不能在idea中很好地显示,在eclipse里很正常,于是切换到eclipse,没用几下就放弃了,eclipse的Scala插件实在太不成熟了,简单的命名重构居然把我的代码改的面目全非,通不过编译了,相比之下idea的Scala插件虽然也有一些问题,但基本还是能用的。google看能不能在idea里正常显示monaco,于是找到这里,2010年的问题,看来这个问题已经存在很久了。
看了回复,大致是两个解决办法:修改字体文件
修改jdk
先试简单的办法,用fontforge把字体的hints和Instructions去掉,一看,果然显示正常了,但一编辑,问题就来了,光标位置字符会出现重叠,根本不能用,看来不是这么简单可以解决的,于是试plan B,参考openJDK fontfix修改代码。
和Linux一样,openJDK也是用freeType2来渲染字体,但相比较,openJDK存在以下几点不同:Linux下的fontconfig可以对单个字体配置不同的渲染参数,但openJDK只能全局设置,就是awt.useSystemAAFontSettings这个参数了,这造成了某些字体不能很好地显示,这可以说是最大的局限
不能使用autohint
hintslight也不能用
lcdfilter没有开启
要解决这些问题,一种方法是在awt.useSystemAAFontSettings参数之外再为JDK增加字体配置信息,这就比较复杂了,改动太大;还是一种方法是直接读取系统的配置信息,这个简单一些,本文就采用这个方案,并且把系统限定为Linux,字体配置采用fontconfig,所以不能在windows下编译。
openJDK的字体渲染是在jdk/src/share/native/sun/font/freetypeScaler.c这个文件中完成的,只需要修改一个文件就行了。
第一步首先要读取Linux fontconfig的字体配置信息,增加下面两个函数:
需要说明的是,虽然是想全部基于fontconfig的配置信息来渲染字体,但是java的AA设置不仅可以通过awt.useSystemAAFontSettings参数来设置,还可以在java程序内指定,java渲染字体的时候也会根据AA来做一些不同的处理,所以,不能简单地忽略AA设置,而全部采用fontconfig的配置,否则就可能导致显示不正常。最终的结果是fontconfig和awt.useSystemAAFontSettings合在一起来配置openJDK的字体。
awt.useSystemAAFontSettings有4个值:on,off,lcd,lcdv,就是要不要antialias,要的话用哪种antialias算法,它覆盖了fontconfig中的antialias,rgba这两个配置项和hintstyle的部分配置参数,所以读取fontconfig配置信息时,会忽略antialias和rgba这两个配置项,hintstyle的值也是优先采用awt.useSystemAAFontSettings的值,没有覆盖到的才会用fontconfig hintstyle中配置的值(hintslight)。
实际地渲染是在Java_sun_font_FreetypeFontScaler_getGlyphImageNative这个函数中完成的,修改如下:
因为使用了fontconfig的函数,别忘了在文件头上加上#include <fontconfig/fontconfig.h>,同时Make文件也得改一下,具体参考openJDK fontfix。好了,重新build openJDK吧,如何build参考openJDK fontfix的build脚本或这里, build完再运行idea,看看字体是不是跟eclipse里一样了,这下不用羡慕eclipse漂亮的字体了吧。
最后再次说明一下,请注意freetypeScaler.c是放在share/native下的,也就是要求是跨平台的,但fontconfig.h是特定于linux的,所以这样改是破坏了跨平台性的,我只是改来自己用用。如果有需要,可以下载附件里patch,应用然后自己编译一下。
看了回复,大致是两个解决办法:修改字体文件
修改jdk
先试简单的办法,用fontforge把字体的hints和Instructions去掉,一看,果然显示正常了,但一编辑,问题就来了,光标位置字符会出现重叠,根本不能用,看来不是这么简单可以解决的,于是试plan B,参考openJDK fontfix修改代码。
和Linux一样,openJDK也是用freeType2来渲染字体,但相比较,openJDK存在以下几点不同:Linux下的fontconfig可以对单个字体配置不同的渲染参数,但openJDK只能全局设置,就是awt.useSystemAAFontSettings这个参数了,这造成了某些字体不能很好地显示,这可以说是最大的局限
不能使用autohint
hintslight也不能用
lcdfilter没有开启
要解决这些问题,一种方法是在awt.useSystemAAFontSettings参数之外再为JDK增加字体配置信息,这就比较复杂了,改动太大;还是一种方法是直接读取系统的配置信息,这个简单一些,本文就采用这个方案,并且把系统限定为Linux,字体配置采用fontconfig,所以不能在windows下编译。
openJDK的字体渲染是在jdk/src/share/native/sun/font/freetypeScaler.c这个文件中完成的,只需要修改一个文件就行了。
第一步首先要读取Linux fontconfig的字体配置信息,增加下面两个函数:
static FcPattern* matchedPattern(const FcChar8* family, double ptSize) { FcPattern* fcPattern = 0; fcPattern = FcPatternCreate(); FcValue fcValue; fcValue.type = FcTypeString; fcValue.u.s = family; FcPatternAdd(fcPattern, FC_FAMILY, fcValue, FcTrue); FcPatternAddBool(fcPattern, FC_SCALABLE, FcTrue); FcPatternAddDouble(fcPattern, FC_SIZE, ptSize); FcConfigSubstitute(0, fcPattern, FcMatchPattern); FcDefaultSubstitute(fcPattern); FcResult res; FcPattern *pattern = 0; pattern = FcFontMatch(0, fcPattern, &res); FcPatternDestroy(fcPattern); return pattern; } typedef struct { FT_Int32 loadFlags; FT_Render_Mode renderMode; FT_LcdFilter lcdFilter; } RenderProperty; static void readFontconfig(FTScalerInfo* scalerInfo, FTScalerContext* context, RenderProperty* rp) { FcPattern *pattern = matchedPattern((const FcChar8 *)scalerInfo->face->family_name, context->ptsz); FT_Int32 load_flags = FT_LOAD_DEFAULT; FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL; FT_LcdFilter lcd_filter = FT_LCD_FILTER_NONE; if (TEXT_AA_OFF == context->aaType) { load_flags = FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO; render_mode = FT_RENDER_MODE_MONO; } else { FcBool hinting = FcTrue; FcPatternGetBool (pattern, FC_HINTING, 0, &hinting); FcBool autohint = FcFalse; FcPatternGetBool(pattern, FC_AUTOHINT, 0, &autohint); int hint_style = FC_HINT_FULL; FcPatternGetInteger(pattern, FC_HINT_STYLE, 0, &hint_style); if (!hinting || hint_style == FC_HINT_NONE) { load_flags |= FT_LOAD_NO_HINTING; if (autohint) load_flags |= FT_LOAD_FORCE_AUTOHINT; } else if (FC_HINT_NONE < hint_style && hint_style < FC_HINT_FULL) { load_flags |= FT_LOAD_TARGET_LIGHT; render_mode = FT_RENDER_MODE_LIGHT; } else load_flags |= FT_LOAD_TARGET_NORMAL; switch (context->aaType) { case TEXT_AA_LCD_HRGB: case TEXT_AA_LCD_HBGR: load_flags |= FT_LOAD_TARGET_LCD; render_mode = FT_RENDER_MODE_LCD; break; case TEXT_AA_LCD_VRGB: case TEXT_AA_LCD_VBGR: load_flags |= FT_LOAD_TARGET_LCD_V; render_mode = FT_RENDER_MODE_LCD_V; } } if (FT_RENDER_MODE_LCD_V == render_mode || FT_RENDER_MODE_LCD == render_mode) { int lcdfilter = FC_LCD_NONE; FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &lcdfilter); switch (lcdfilter) { case FC_LCD_NONE: lcd_filter = FT_LCD_FILTER_NONE; break; case FC_LCD_LIGHT: lcd_filter = FT_LCD_FILTER_LIGHT; break; case FC_LCD_LEGACY: lcd_filter = FT_LCD_FILTER_LEGACY; break; default: lcd_filter = FT_LCD_FILTER_DEFAULT; } } FcPatternDestroy(pattern); rp->loadFlags = load_flags; rp->renderMode = render_mode; rp->lcdFilter = lcd_filter; }
需要说明的是,虽然是想全部基于fontconfig的配置信息来渲染字体,但是java的AA设置不仅可以通过awt.useSystemAAFontSettings参数来设置,还可以在java程序内指定,java渲染字体的时候也会根据AA来做一些不同的处理,所以,不能简单地忽略AA设置,而全部采用fontconfig的配置,否则就可能导致显示不正常。最终的结果是fontconfig和awt.useSystemAAFontSettings合在一起来配置openJDK的字体。
awt.useSystemAAFontSettings有4个值:on,off,lcd,lcdv,就是要不要antialias,要的话用哪种antialias算法,它覆盖了fontconfig中的antialias,rgba这两个配置项和hintstyle的部分配置参数,所以读取fontconfig配置信息时,会忽略antialias和rgba这两个配置项,hintstyle的值也是优先采用awt.useSystemAAFontSettings的值,没有覆盖到的才会用fontconfig hintstyle中配置的值(hintslight)。
实际地渲染是在Java_sun_font_FreetypeFontScaler_getGlyphImageNative这个函数中完成的,修改如下:
//先在函数开始的地方加上这一段,创建一个RenderProperty结构体,用来保存读取的字体配置信息 RenderProperty* rp = NULL; rp = (RenderProperty*) calloc(1, sizeof(RenderProperty)); if (NULL == rp) { return ptr_to_jlong(getNullGlyphImage()); } /**这段要注释掉 if (context->aaType == TEXT_AA_OFF) { target = FT_LOAD_TARGET_MONO; } else if (context->aaType == TEXT_AA_ON) { target = FT_LOAD_TARGET_NORMAL; } else if (context->aaType == TEXT_AA_LCD_HRGB || context->aaType == TEXT_AA_LCD_HBGR) { target = FT_LOAD_TARGET_LCD; } else { target = FT_LOAD_TARGET_LCD_V; } renderFlags |= target; */ //读取配置,设置lcdfilter readFontconfig(scalerInfo, context, rp); renderFlags |= rp->loadFlags; FT_Library_SetLcdFilter(scalerInfo->library, rp->lcdFilter); glyph_index = FT_Get_Char_Index(scalerInfo->face, glyphCode); error = FT_Load_Glyph(scalerInfo->face, glyphCode, renderFlags); ...... if (ftglyph->format == FT_GLYPH_FORMAT_OUTLINE) { FT_Render_Glyph(ftglyph, rp->renderMode);//renderMode改成读取过来的 } free(rp);
因为使用了fontconfig的函数,别忘了在文件头上加上#include <fontconfig/fontconfig.h>,同时Make文件也得改一下,具体参考openJDK fontfix。好了,重新build openJDK吧,如何build参考openJDK fontfix的build脚本或这里, build完再运行idea,看看字体是不是跟eclipse里一样了,这下不用羡慕eclipse漂亮的字体了吧。
最后再次说明一下,请注意freetypeScaler.c是放在share/native下的,也就是要求是跨平台的,但fontconfig.h是特定于linux的,所以这样改是破坏了跨平台性的,我只是改来自己用用。如果有需要,可以下载附件里patch,应用然后自己编译一下。
相关文章推荐
- linux shell 的here document 用法 (cat << EOF)
- ShellExecute使用详解
- AWK调用SHELL,并将变量传递给SHELL
- 编写shell时,let: not found
- shell命令执行hive脚本(hive交互,hive的shell编程)
- shell命令执行hive脚本(hive交互,hive的shell编程)
- Xshell连接linux(deepin)时提示ssh服务器拒绝了密码,请再试一次
- 通过Git WebHooks+脚本实现自动更新发布代码之shell脚本
- 通过Git WebHooks+脚本实现自动更新发布代码之shell脚本
- android adb shell 查询进程流量情况
- 利用PowerShell更改Search Service Account和删除旧的Search Service topology
- shell 日志分析 获取code的统计——grep awk group功能使用
- 【Linux】之shell特殊变量整理
- 几款xshell绝佳配色方案
- shell脚本编写
- shell编程之正则表达式
- shell命令执行的详细时间查看命令time
- shell命令使用Hadoop归档文件
- git shell
- linux输入ifconfig后报“bash:ifoco…