robotools / compositor

A basic OpenType GSUB and GPOS layout engine.
MIT License
30 stars 11 forks source link

Right-to-left problem with "mark" GPOS #24

Open andyclymer opened 6 years ago

andyclymer commented 6 years ago

A student of mine found a problem in the FeaturePreview.roboFontExt that I traced back to Compositor, but I'm a little bit lost with how to fix it — the handling of GPOS mark positioning doesn't seem to be working properly when the text is right-to-left.

Here's an example as I visualize the problem in DrawBot using Noto Sans Hebrew as a sample font:

image

The green text is in a normal text box in DrawBot, and the marks are positioned correctly, as a control. The red text is when rightToLeft is True, the direction is correct but the positioning is off by one base character. The purple text shows that when the text is processed in the incorrect order the mark positioning is correct.

I'm also attaching my DrawBot script below if it helps with testing the problem, and I'm testing with the latest release of Noto which can be found here: https://www.google.com/get/noto/

from compositor import Font as cFont
from fontTools.pens.cocoaPen import CocoaPen

size(200, 200)

fontPath = "./NotoSansHebrew-Medium.ttf"

def drawRecords(glyphRecords):
    for record in glyphRecords:
        save()
        translate(record.xPlacement, record.yPlacement)
        glyph = f[record.glyphName]
        pen = CocoaPen(f)
        glyph.draw(pen)
        path = BezierPath()
        drawPath(pen.path)
        restore()
        translate(glyph.width)

# Green text in a text box,
# Correct positioning

font("Lucida Grande")
fontSize(8)
fill(0)
text("In a text box", (10, 150))

font(fontPath)
fontSize(30)
fill(0, 0.5, 0, 1)
text("בַּיִת", (100, 150)) # oooh, this line looks weird but it works

# Red text with Compositor
# rightToLeft set to True
# Correct direction, incorrect mark positioning

font("Lucida Grande")
fontSize(8)
fill(0)
text("rightToLeft = True", (10, 100))

fill(0.75, 0, 0, 1)

save()
scale(0.05, 0.05)
translate(2000, 2000)
f = cFont(fontPath)
glyphRecords = f.process(u"בַּיִת", script="hebr", rightToLeft=True)
drawRecords(glyphRecords)
restore()

# Purple text with Compositor
# rightToLeft = False
# Incorrect direction, but correct mark positioning

font("Lucida Grande")
fontSize(8)
fill(0)
text("rightToLeft = False", (10, 50))

fill(0.5, 0, 0.5, 1)

save()
scale(0.05, 0.05)
translate(2000, 1000)
f = cFont(fontPath)
glyphRecords = f.process(u"בַּיִת", script="hebr", rightToLeft=False)
drawRecords(glyphRecords)
restore()