如何为 IDWriteTextLayout 指定歧义字符的方向性?

Posted

技术标签:

【中文标题】如何为 IDWriteTextLayout 指定歧义字符的方向性?【英文标题】:How do I specify directionality of ambiguous characters to IDWriteTextLayout? 【发布时间】:2016-01-22 23:25:16 【问题描述】:

有些字符的方向性不明确,例如空格和标点符号。这可能会导致文本布局情况,在没有访问附加数据来解决歧义的情况下,似乎没有一个正确的布局。考虑这段文字:

\u05e9\u05e0\u05d1\u05d2abcd!

这是四个希伯来字符(明确从右到左)、四个英文字符(明确从左到右)和一个标点符号(不明确)。如果我在IDWriteTextLayoutDWRITE_READING_DIRECTION_RIGHT_TO_LEFT 中布局该字符串,我会得到以下信息:

标点符号似乎被视为从右到左的字符,它在英语左侧开始一个新的从右到左的块,这似乎非常合理,特别是考虑到从右到左是指定的阅读方向。但是,将标点符号视为与嵌入的从左到右英文文本相关联的从左到右字符也是完全合理的,这意味着它应该出现在“d”的右侧。

我的应用确切地知道它希望如何对待这个角色。如何将该数据传递给 IDWriteTextLayout 以解决这种歧义?

我找到了SetLocaleName 方法并认为它一定是答案,但我似乎根本无法让它影响结果。在创建IDWriteTextFormat(然后用于创建IDWriteTextLayout)时,我还发现了localeName 参数。

如果我的目标通常是嵌入美国英语的希伯来语文本,我想我想在IDWriteTextFormat 上使用语言环境he,然后使用SetLocaleName 覆盖它字符范围 [4-9] 上的语言环境 en-US。但是,这样做没有任何效果。事实上,我无法让这些地方使用的任何语言环境组合对布局产生任何影响,无论是将它们限制在子范围内还是将它们应用于整个字符串。

我认为这些 API 应该用于此目的是不是错了?如果是这样,我应该使用哪些 API?还是真的没有办法告诉IDWriteTextLayout 以不同的方式解决这种歧义?我可能使用错误的 API 吗?这是我用来创建 IDWriteTextLayout 的测试代码:

TestTextRenderer::TestTextRenderer(const std::shared_ptr<DX::DeviceResources>& deviceResources) : 
    m_deviceResources(deviceResources),
    m_text(L"\u05e9\u05e0\u05d1\u05d2abcd!"),
    m_readingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT),
    m_formatLocale(L"en-US"),
    m_layoutLocale(L"en-US")

    ComPtr<IDWriteTextFormat> textFormat;
    DX::ThrowIfFailed(
        m_deviceResources->GetDWriteFactory()->CreateTextFormat(
            L"Segoe UI",
            nullptr,
            DWRITE_FONT_WEIGHT_MEDIUM,
            DWRITE_FONT_STYLE_NORMAL,
            DWRITE_FONT_STRETCH_NORMAL,
            24.0f,
            m_formatLocale.c_str(),
            &textFormat
        )
    );
    DX::ThrowIfFailed(textFormat->SetReadingDirection(m_readingDirection));

    DX::ThrowIfFailed(
        m_deviceResources->GetDWriteFactory()->CreateTextLayout(
            m_text.c_str(),
            (uint32) m_text.length(),
            textFormat.Get(),
            250.0f,
            100.0f,
            &m_textLayout
        )
    );

    DWRITE_TEXT_RANGE all0u, m_text.size();
    DX::ThrowIfFailed(m_textLayout->SetLocaleName(m_layoutLocale.c_str(), all));

    DX::ThrowIfFailed(m_deviceResources->GetD2DFactory()->CreateDrawingStateBlock(&m_stateBlock));
    CreateDeviceDependentResources();

【问题讨论】:

【参考方案1】:

我认为从 Unicode BiDi 算法的角度来看没有任何歧义。初始方向设置为IDWriteTextFormatIDWriteTextLayout 至关重要,但之后运行方向将严格从代码点派生。

设置语言环境不会改变方向,但可能会影响造型,最终结果取决于运行字体的特定功能。

我认为您可以在这部分文本周围使用 LRE/PDF 控件完成 abcd!... 输出。

【讨论】:

已确认,使用控制字符 LRE 和 PDF 具有预期的效果,并且似乎是处理此问题的正确方法。

以上是关于如何为 IDWriteTextLayout 指定歧义字符的方向性?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Jcrop 'setSelect' 选项指定自定义值?

如何为 spectrify python 包指定 s3 配置?

如何为 MSBuild 指定平台?

如何为 EmrCreateJobFlowOperator 指定配置文件?

如何为 XDocument 指定 xmlns?

如何为变更日志表指定架构位置