DirectWrite 未针对变音符号进行调整

问题描述

我目前正在调试我编写的一些 DirectWrite 代码,因为我在使用非英语字符进行测试时遇到了问题。主要是让多个 Unicode 字符返回正确的索引。

编辑:经过进一步研究,我认为问题是变音符号,应该以某种方式组合额外的字符。 DWRITE_SHAPING_GLYPH_PROPERTIES 字段 isDiacritic 确实为最后一个 Unicode 代码点返回 1。然而,塑造过程似乎根本没有考虑到这些。 GetGlyPHPlacements 为变音符号字形的前进和偏移返回 0。 LSB 大约为 -5,但这不足以偏移到正确的位置。有谁知道 DirectWrite 在塑造过程中应该在哪里考虑变音符号以及如何考虑?

考虑这个字符:œ̃

显示一个字符(通过大多数文本编辑器),但有两个代码点:U+0153 U+0303

我如何在 GetGlyphs() 中说明这一点,因为它们是单独的代码点?在我的代码中,它返回两个不同的索引 (177,1123)一个集群 (0,0)

这就是最终呈现的内容

image

这与单独呈现的两个代码点一致,但与实际字符不一致。 GetGlyphs() 返回的实际索引计数为 2。

我的问题如下:

  1. 这是否应该从 GetGlyphs() 返回一个索引?

  2. 我是否应该得到一个索引,或者两个不同的索引是否有某种魔法,在这个过程的某个阶段,它们在字形运行中组合在一起?

  3. 如果我应该得到一个索引,这些索引组合在什么过程/功能上?也许是我的 ScriptAnalysis 中的错误?试图缩小问题的范围。

  4. 我应该使用字符的长度而不包括代码点吗?

我很抱歉,因为我对字体/Unicode 以及整个塑造过程的内部运作不是很了解。

这是我用来获取索引和预付款的过程的一些代码

text_length = len(text.encode('utf-16-le')) // 2
text_buffer = create_unicode_buffer(text,text_length)

self._text_analysis.GenerateResults(self._analyzer,text_buffer,len(text_buffer))

# Formula for text buffer size from Microsoft.
max_glyph_size = int(3 * text_length / 2 + 16)

length = text_length
clusters = (UINT16 * length)()
text_props = (DWRITE_SHAPING_TEXT_PROPERTIES * length)()
indices = (UINT16 * max_glyph_size)()
glyph_props = (DWRITE_SHAPING_GLYPH_PROPERTIES * max_glyph_size)()
actual_count = UINT32()

self._analyzer.GetGlyphs(text_buffer,len(text_buffer),self.font.font_face,False,# sideways
                         False,# rtl
                         self._text_analysis.script,# scriptAnalysis
                         None,# localName
                         None,# numberSub
                         None,# typo features
                         None,# feature range length
                         0,# feature range
                         max_glyph_size,# max glyph size
                         clusters,# cluster map
                         text_props,# text props
                         indices,# glyph indices
                         glyph_props,# glyph pops
                         byref(actual_count)  # glyph count
                     )

advances = (FLOAT * length)()
offsets = (DWRITE_GLYPH_OFFSET * length)()
self._analyzer.GetGlyPHPlacements(text_buffer,clusters,text_props,text_length,indices,glyph_props,actual_count,self.font.font_metrics.designUnitsPerEm,self._text_analysis.script,self.font.locale,None,advances,offsets)

编辑:这是渲染代码

def render_single_glyph(self,font_face,indice,advance,offset,metrics):
    """Renders a single glyph using D2D DrawGlyphRun"""
    glyph_width,glyph_height,lsb,font_advance = metrics

    # Slicing an array turns it into a python object. Maybe a better way to keep it a ctypes value?
    new_indice = (UINT16 * 1)(indice)
    new_advance = (FLOAT * 1)(advance)

    run = self._get_single_glyph_run(font_face,self.font._real_size,new_indice,# indice,new_advance,# advance,pointer(offset),# offset,False)


    offset_x = 0
    if lsb < 0:
        # Negative LSB: we shift the layout rect to the right
        # Otherwise we will cut the left part of the glyph
        offset_x = math.ceil(abs(lsb))

    font_height = (self.font.font_metrics.ascent + self.font.font_metrics.descent) * self.font.font_scale_ratio

    # Create new bitmap.
    self._create_bitmap(int(math.ceil(glyph_width)),int(math.ceil(font_height)))

    # This offsets the characters if needed.
    point = D2D_POINT_2F(offset_x,int(math.ceil(font_height)))

    self._render_target.BeginDraw()

    self._render_target.Clear(transparent)

    self._render_target.DrawGlyphRun(point,run,self.brush,DWRITE_MEASURING_MODE_NATURAL)

    self._render_target.EndDraw(None,None)
    image = wic_decoder.get_image(self._bitmap)

    glyph = self.font.create_glyph(image)
    glyph.set_bearings(self.font.descent,offset_x,round(advance * self.font.font_scale_ratio))  # baseline,advance
    return glyph

解决方法

塑造过程由您的输入控制,即(文本、字体、语言环境、脚本、用户功能)。所有这些都会影响你得到的结果。具体回答您的问题:

这应该从 GetGlyphs() 返回一个索引吗?

这主要由您的字体定义。

我是否应该得到一个指数,或者是否涉及一些魔法 有两个不同的指数,在这个过程的某个阶段,他们 在字形运行中组合?

GetGlyphs() 单次运行。根据每个脚本定义的整形规则和字体中定义的转换,字形可以自由地形成一个簇。

如果我应该得到一个指标,这些是什么过程/功能 指数组合在?也许是我的 ScriptAnalysis 中的错误?尝试去 缩小问题所在。

基本上,如果你的输入参数是正确的,你就会得到你所得到的输出,你无法真正控制它的核心。您可以做的是在 Uniscribe、CoreText (macos) 和 Chromium/Firefox (harfbuzz) 上测试相同文本和字体的输出,看看它们是否不同。

我应该使用字符的长度而不是包含 代码点?

我没有得到这个。