8

我能够找到以下确定Unicode-16字体是否支持字符的方法。不幸的是,这不适用于代理对 Unicode characters,因为WCRANGE函数支持的结构GetFontUnicodeRanges仅返回WCHAR(16 位)参数作为输出。

这是我正在尝试做的一个例子:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HFONT hFont = NULL;

    switch (message)
    {
        case WM_CREATE:
        {
            LOGFONT lf = {0};
            lf.lfHeight = -64;
            ::StringCchCopy(lf.lfFaceName, _countof(lf.lfFaceName), L"Arial");

            hFont = ::CreateFontIndirect(&lf);
        }
        break;

        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);

            RECT rcClient = {0};
            ::GetClientRect(hWnd, &rcClient);

            HGDIOBJ hOldFont = ::SelectObject(hdc, hFont);

            LPCTSTR pStr = L">\U0001F609<";
            int nLn = wcslen(pStr);

            RECT rc = {20, 20, rcClient.right, rcClient.bottom};
            ::DrawText(hdc, pStr, nLn, &rc, DT_NOPREFIX | DT_SINGLELINE);

            ::SelectObject(hdc, hOldFont);

            EndPaint(hWnd, &ps);
        }
        break;

    //....

如果我在 Windows 10 上运行它,我会得到:

在此处输入图像描述

但这就是我在 Windows 7 上得到的:

在此处输入图像描述

那么如何判断中间字符是否不会被渲染呢?


PS。我还尝试使用文档不完整的 Uniscribe本教程的修改版本作为示例。但无论我怎么做,都未能在 Win10 和 Win7 之间产生明显的结果。如果它有助于回答这个问题,这是我尝试过的代码:

//Call from WM_PAINT handler
std::wstring str;
test02(hdc, pStr, str);

RECT rc0 = {0, 200, rcClient.right, rcClient.bottom};
::DrawText(hdc, str.c_str(), str.size(), &rc0, DT_NOPREFIX | DT_SINGLELINE);

接着:

void test02(HDC hDc, LPCTSTR pStr, std::wstring& str)
{
    //'str' = receives debugging outcome (needs to be printed on the screen)

    //SOURCE:
    //      https://maxradi.us/documents/uniscribe/

    HRESULT hr;
    SCRIPT_STRING_ANALYSIS ssa = {0};

    int nLn = wcslen(pStr);

    hr = ::ScriptStringAnalyse(hDc,
        pStr,
        nLn,
        1024,
        -1,
        SSA_GLYPHS,
        0, NULL, NULL, NULL, NULL, NULL, &ssa);

    if(SUCCEEDED(hr))
    {
        const SCRIPT_PROPERTIES **g_ppScriptProperties;
        int g_iMaxScript;

        hr = ::ScriptGetProperties(&g_ppScriptProperties, &g_iMaxScript);
        if(SUCCEEDED(hr))
        {
            const int cMaxItems = 20;
            SCRIPT_ITEM si[cMaxItems + 1];
            SCRIPT_ITEM *pItems = si;
            int cItems;                 //Receives number of glyphs

            SCRIPT_CONTROL scrCtrl = {0};
            SCRIPT_STATE scrState = {0};

            hr = ::ScriptItemize(pStr, nLn, cMaxItems, &scrCtrl, &scrState, pItems, &cItems);
            if(SUCCEEDED(hr))
            {
                FormatAdd2(str, L"cItems=%d: ", cItems);

                int nCntGlyphs = nLn * 4;
                WORD* pGlyphs = new WORD[nCntGlyphs];
                WORD* pLogClust = new WORD[nLn];
                SCRIPT_VISATTR* pSVs = new SCRIPT_VISATTR[nCntGlyphs];

                //Go through each run
                for(int i = 0; i < cItems; i++)
                {
                    FormatAdd2(str, L"[%d]:", i);

                    SCRIPT_CACHE sc = NULL;
                    int nCntGlyphsWrtn = 0;
                    int iPos = pItems[i].iCharPos;
                    const WCHAR* pP = &pStr[iPos];
                    int cChars = i + 1 < cItems ? pItems[i + 1].iCharPos - iPos : nLn - iPos;

                    hr = ::ScriptShape(hDc, &sc, pP, cChars,
                        nCntGlyphs, &pItems[i].a, pGlyphs, pLogClust, pSVs, &nCntGlyphsWrtn);

                    if(SUCCEEDED(hr))
                    {
                        std::wstring strGlyphs;
                        for(int g = 0; g < nCntGlyphsWrtn; g++)
                        {
                            FormatAdd2(strGlyphs, L"%02X,", pGlyphs[g]);
                        }

                        std::wstring strLogClust;
                        for(int w = 0; w < cChars; w++)
                        {
                            FormatAdd2(strLogClust, L"%02X,", pLogClust[w]);
                        }

                        std::wstring strSVs;
                        for(int g = 0; g < nCntGlyphsWrtn; g++)
                        {
                            FormatAdd2(strSVs, L"%02X,", pSVs[g]);
                        }

                        FormatAdd2(str, L"c=%d {G:%s LC:%s SV:%s} ", nCntGlyphsWrtn, strGlyphs.c_str(), strLogClust.c_str(), strSVs.c_str());


                        int* pAdvances = new int[nCntGlyphsWrtn];
                        GOFFSET* pOffsets = new GOFFSET[nCntGlyphsWrtn];
                        ABC abc = {0};

                        hr = ::ScriptPlace(hDc, &sc, pGlyphs, nCntGlyphsWrtn, pSVs, &pItems[i].a, pAdvances, pOffsets, &abc);
                        if(SUCCEEDED(hr))
                        {
                            std::wstring strAdvs;
                            for(int g = 0; g < nCntGlyphsWrtn; g++)
                            {
                                FormatAdd2(strAdvs, L"%02X,", pAdvances[g]);
                            }

                            std::wstring strOffs;
                            for(int g = 0; g < nCntGlyphsWrtn; g++)
                            {
                                FormatAdd2(strOffs, L"u=%02X v=%02X,", pOffsets[g].du, pOffsets[g].dv);
                            }


                            FormatAdd2(str, L"{a=%d,b=%d,c=%d} {A:%s OF:%s}", abc.abcA, abc.abcB, abc.abcC, strAdvs.c_str(), strOffs.c_str());
                        }


                        delete[] pAdvances;
                        delete[] pOffsets;

                    }



                    //Clear cache
                    hr = ::ScriptFreeCache(&sc);
                    assert(SUCCEEDED(hr));
                }

                delete[] pSVs;
                delete[] pGlyphs;
                delete[] pLogClust;
            }
        }

        hr = ::ScriptStringFree(&ssa);
        assert(SUCCEEDED(hr));
    }
}

std::wstring& FormatAdd2(std::wstring& str, LPCTSTR pszFormat, ...)
{
    va_list argList;
    va_start(argList, pszFormat);
    int nSz = _vsctprintf(pszFormat, argList) + 1;

    TCHAR* pBuff = new TCHAR[nSz];      //One char for last null
    pBuff[0] = 0;
    _vstprintf_s(pBuff, nSz, pszFormat, argList);
    pBuff[nSz - 1] = 0;

    str.append(pBuff);

    delete[] pBuff;

    va_end(argList);

    return str;
}

编辑:我能够创建一个演示 GUI 应用程序,演示下面Barmak Shemirani建议的解决方案。

4

1 回答 1

7
于 2019-01-05T15:41:45.843 回答