首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检查Unicode字符是否显示或豆腐

检查Unicode字符是否显示或豆腐
EN

Stack Overflow用户
提问于 2017-12-15 22:42:43
回答 2查看 1.7K关注 0票数 6

我的问题类似于这一个,但稍微向前迈进了一步.

在我的Win32程序中,我有一些菜单按钮,菜单上有BMP上面的Unicode字符,比如U+1F5A4 (UTF-16代位对0xD83D 0xDDA4)。

在Windows 10中,系统字体Segoe没有这个字形:它被自动替换为字体Segoe符号中的一个字形,并在按钮中正确显示,这要归功于一个名为字体链接(或字体回退,我仍然不太清楚)的过程。

但在Windows 7中,字体链接带来的字体也没有此字形,代理项对显示为两个空框▯▯。在Windows中,Tahoma字体也是如此。

我希望避免使用这些替换框,方法是在分配到按钮之前或之后解析文本,并用一些常见的ASCII字符替换丢失的字形。

我试过GetGlyphOutlineScriptGetCMapGetFontUnicodeRangesGetGlyphIndices,但它们不支持代孕对。

我还尝试过支持代理项对的GetCharacterPlacement和Uniscribe ScriptItemize+ScriptShape,但是所有这些函数只搜索HDC (Segoe )的基本字体,它们不搜索最终回退字体(Segoe符号),这是一个提供字形的字体。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink --这是我看过的地方,但我真的认为它不在那里--系统需要链接到的字体。

问题是:我如何知道系统的字体链接是否会产生正确的字形或豆腐盒?

编辑

我找到了某种解决方案,复制了这段代码并添加了最后一个GetCharacterPlacement

代码语言:javascript
复制
#include <usp10.h>

wchar_t *checkGlyphExist( HWND hwnd, wchar_t *sUnicode, wchar_t *sLimited ) {

    // Create metafile
    HDC hdc = GetDC( hwnd );
    HDC metaFileDC = CreateEnhMetaFile( hdc, NULL, NULL, NULL );

    // Select menu font
    NONCLIENTMETRICSW ncm;
    ncm.cbSize = sizeof(ncm);
    SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0 );
    HFONT hFont = CreateFontIndirectW( &(ncm.lfMenuFont) );
    SelectObject( metaFileDC, hFont );
    wprintf( L"%s\n", ncm.lfMenuFont.lfFaceName );  // 'Segoe UI' in Win 10 and 7 (ok)
                                                    // 'Tahoma' in Win XP (ok)

    // Use the meta file to intercept the fallback font chosen by Uniscribe
    SCRIPT_STRING_ANALYSIS ssa;
    ScriptStringAnalyse( metaFileDC, sUnicode, wcslen(sUnicode), 0, -1,
                      SSA_METAFILE | SSA_FALLBACK | SSA_GLYPHS | SSA_LINK,  
                      0, NULL, NULL, NULL, NULL, NULL, &ssa );
    ScriptStringFree( &ssa );
    HENHMETAFILE metaFile = CloseEnhMetaFile(metaFileDC);
    LOGFONTW logFont = {0};
    EnumEnhMetaFile( 0, metaFile, metaFileEnumProc, &logFont, NULL );
    DeleteEnhMetaFile( metaFile );
    wprintf( L"%s\n", logFont.lfFaceName );
        // 'Segoe UI Symbol' in Win 10 (ok)
        // 'Microsoft Sans Serif' in Win 7 (wrong, should be 'Segoe UI Symbol')
        // 'Tahoma' in Win XP for characters above 0xFFFF (wrong, should be 'Microsoft Sans Serif', I guess)
    
    // Get glyph indices for the 'sUnicode' string
    hFont = CreateFontIndirectW( &logFont );
    SelectObject( hdc, hFont );
    GCP_RESULTSW infoStr = {0};
    infoStr.lStructSize = sizeof(GCP_RESULTSW);
    wchar_t tempStr[wcslen(sUnicode)];  
    wcscpy( tempStr, sUnicode );
    infoStr.lpGlyphs = tempStr;
    infoStr.nGlyphs = wcslen(tempStr);
    GetCharacterPlacementW( hdc, tempStr, wcslen(tempStr), 0, &infoStr, GCP_GLYPHSHAPE );
    ReleaseDC( hwnd, hdc );

    // Return one string
    if( infoStr.lpGlyphs[0] == 3 || // for Windows 7 and 10
        infoStr.lpGlyphs[0] == 0 )  // for Windows XP
        return sLimited;
    else
        return sUnicode;
}

// Callback function to intercept font creation
int CALLBACK metaFileEnumProc( HDC hdc, HANDLETABLE *table, const ENHMETARECORD *record,
                            int tableEntries, LPARAM logFont ) {
    if( record->iType == EMR_EXTCREATEFONTINDIRECTW ) {
        const EMREXTCREATEFONTINDIRECTW* fontRecord = (const EMREXTCREATEFONTINDIRECTW *)record;
        *(LOGFONTW *)logFont = fontRecord->elfw.elfLogFont;
    }
    return 1;
}

你可以用checkGlyphExist( hWnd, L"", L"<3" );来调用它

我在Windows 10和两台虚拟机上进行了测试:Windows7Professional,Windows SP2。

它运行得很好,但当基本字体中缺少字形时,EnumEnhMetaFile检索的回退字体仍然存在两个问题:

  • 在Windows 7中,总是微软的Sans Serif,但真正的备用字体应该是Segoe UI符号。
  • 在Windows中是Tahoma而不是Microsoft,但只适用于代理项对字符(对于BMP字符是Microsoft,我想这是正确的)。

有人能帮我解决这个问题吗?

EN

回答 2

Stack Overflow用户

发布于 2017-12-16 10:44:42

首先,您必须确保在Win7和Win10上都使用相同的API。低级别的gdi32 API一般不支持代理项对,而更新的DirectWrite在每个级别上都支持代理项对。接下来要记住的是,字体回退(字体链接是一种不同的东西)数据在发布版本中有所不同,它不是用户可以访问的内容,也是不可修改的。

第二件事是检查Win7是否首先在U+1F5A4上为符号提供字体,它可能只是在以后的版本中引入的。

基本上,如果您使用的系统呈现功能,旧的或新的,您不应该控制退路的大部分时间,如果它不工作,它通常意味着它将无法工作。DirectWrite允许自定义回退列表,例如,可以将U+1F5A4显式地分配给您想要的任何字体,支持它,包括可以与应用程序捆绑的自定义字体。

如果你想要更详细的答案,你需要给出一些不适合你的资料。

票数 0
EN

Stack Overflow用户

发布于 2017-12-16 00:11:52

我相信高和低16位的词是很好定义的代孕对。您应该能够通过检查每个16位单词的值范围来识别代理项对。

对于高单词,它应该在0xd 800到0xdbff的范围内,对于较低的单词,它应该在0xdc00到0xdfff的范围内。

如果任何两个“字符”符合此标准,则它们是代理项对。

更多信息请参阅维基百科关于UTF-16的文章。

票数 -3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47840800

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档