Esempio n. 1
0
def test_project_dump_load(tmpdir):
    destPath = pathlib.Path(tmpdir / "test.gggls")
    pr = Project()
    fontPath1 = getFontPath("IBMPlexSans-Regular.ttf")
    pr.addFont(fontPath1, 0)
    fontPath2 = getFontPath("IBMPlexSans-Regular.otf")
    pr.addFont(fontPath2, 0)
    json = pr.asJSON(destPath.parent)
    pr2 = Project.fromJSON(json, destPath.parent)
    for f1, f2 in zip(pr.fonts, pr2.fonts):
        assert f1.fontKey == f2.fontKey
Esempio n. 2
0
async def test_DSFont():
    ufoPath = getFontPath("MutatorSans.designspace")
    font = DSFont(ufoPath, 0)
    await font.load(sys.stderr.write)
    expected = [
        'MutatorSansBoldCondensed.ufo',
        'MutatorSansBoldWide.ufo',
        'MutatorSansLightCondensed.ufo',
        'MutatorSansLightWide.ufo',
    ]
    assert expected == [p.name for p in font.getExternalFiles()]
    run = font.getGlyphRun("ABC")
    ax = [gi.ax for gi in run]
    assert [396, 443, 499] == ax
    # Glyph 'A' has custom vertical glyph metrics in the default master
    run = font.getGlyphRun("A", direction="TTB")
    assert run[0].ax == 0
    assert run[0].ay == -986
    assert run[0].dx == -198
    assert run[0].dy == -777
    # But not at the other masters, so expect defaults there
    run = font.getGlyphRun("A", varLocation=dict(wght=1000), direction="TTB")
    assert run[0].ax == 0
    assert run[0].ay == -900
    assert run[0].dx == -370
    assert run[0].dy == -700
Esempio n. 3
0
def test_pointCollector():
    ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo")
    reader = UFOReader(ufoPath)
    glyphSet = reader.getGlyphSet()
    pen = PointCollector(glyphSet)
    glyphSet["B"].draw(pen)
    assert len(pen.points) == 38
    assert len(pen.tags) == 38
    assert pen.contours == [3, 37]
    assert pen.tags[:12] == [1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1]

    pen = PointCollector(glyphSet, decompose=False)
    glyphSet["Aacute"].draw(pen)
    assert len(pen.points) == 0
    assert pen.contours == []
    assert pen.components == [("A", (1, 0, 0, 1, 0, 0)), ("acute", (1, 0, 0, 1, 484, 20))]

    pen = PointCollector(glyphSet, decompose=True)
    glyphSet["Aacute"].draw(pen)
    assert len(pen.points) == 20
    assert pen.contours == [3, 7, 11, 15, 19]
    assert pen.components == []

    pen = PointCollector(glyphSet)
    glyphSet["O"].draw(pen)
    assert len(pen.points) == 28
    assert pen.contours == [13, 27]
Esempio n. 4
0
def test_shape_getFeatures():
    s = HBShape.fromPath(getFontPath("IBMPlexSans-Regular.ttf"))
    expected = {
        'aalt', 'ccmp', 'dnom', 'frac', 'liga', 'numr', 'ordn', 'salt', 'sinf',
        'ss01', 'ss02', 'ss03', 'ss04', 'ss05', 'subs', 'sups', 'zero'
    }
    assert expected == set(s.getFeatures("GSUB"))
Esempio n. 5
0
async def test_openFonts(fileName,
                         expectedSortInfo,
                         featuresGSUB,
                         featuresGPOS,
                         scripts,
                         axes,
                         ext,
                         location,
                         text,
                         glyphNames,
                         ax):
    fontPath = getFontPath(fileName)
    numFonts, opener, getSortInfo = getOpener(fontPath)
    assert numFonts(fontPath) == 1
    font = opener(fontPath, 0)
    await font.load(None)
    sortInfo = getSortInfo(fontPath, 0)
    assert sortInfo == expectedSortInfo
    assert font.featuresGSUB == featuresGSUB
    assert font.featuresGPOS == featuresGPOS
    assert font.scripts == scripts
    assert font.axes == axes
    run = font.getGlyphRun(text, varLocation=location)
    assert [gi.name for gi in run] == glyphNames
    assert ext == [p.name for p in font.getExternalFiles()]
    if ax is not None:
        assert [gi.ax for gi in run] == ax
Esempio n. 6
0
def test_ufoCharacterMapping_glyphNames():
    ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo")
    reader = UFOReader(ufoPath)
    cmap, revCmap, anchors = fetchCharacterMappingAndAnchors(
        reader.getGlyphSet(), ufoPath, ["A"])
    assert cmap[0x0041] == "A"
    assert revCmap["A"] == [0x0041]
    assert anchors == {"A": [("top", 645, 815)]}
Esempio n. 7
0
def test_getUpdateInfo(tmpdir):
    ufoSource = getFontPath("MutatorSansBoldWideMutated.ufo")
    ufoPath = shutil.copytree(ufoSource, tmpdir / "test.ufo")
    reader = UFOReader(ufoPath, validate=False)
    glyphSet = reader.getGlyphSet()
    cmap, unicodes, anchors = fetchCharacterMappingAndAnchors(glyphSet, ufoPath)

    state = UFOState(reader, glyphSet, getUnicodesAndAnchors=lambda: (unicodes, anchors))

    feaPath = pathlib.Path(reader.fs.getsyspath("/features.fea"))
    feaPath.touch()

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert needsFeaturesUpdate
    assert not needsGlyphUpdate
    assert not needsInfoUpdate
    assert not needsCmapUpdate

    infoPath = pathlib.Path(reader.fs.getsyspath("/fontinfo.plist"))
    infoPath.touch()

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert not needsFeaturesUpdate
    assert not needsGlyphUpdate
    assert needsInfoUpdate
    assert not needsCmapUpdate

    glyph = Glyph("A", None)
    ppen = RecordingPointPen()
    glyphSet.readGlyph("A", glyph, ppen)
    glyph.anchors[0]["x"] = 123
    glyphSet.writeGlyph("A", glyph, ppen.replay)

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert needsFeaturesUpdate
    assert needsGlyphUpdate
    assert not needsInfoUpdate
    assert not needsCmapUpdate

    glyph = Glyph("A", None)
    ppen = RecordingPointPen()
    glyphSet.readGlyph("A", glyph, ppen)
    glyph.unicodes = [123]
    glyphSet.writeGlyph("A", glyph, ppen.replay)

    state = state.newState()
    (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate,
     needsLibUpdate) = state.getUpdateInfo()
    assert not needsFeaturesUpdate
    assert needsGlyphUpdate
    assert not needsInfoUpdate
    assert needsCmapUpdate
Esempio n. 8
0
async def test_project_loadFonts():
    pr = Project()
    fontPath = getFontPath("IBMPlexSans-Regular.ttf")
    pr.addFont(fontPath, 0)
    fii = pr.fonts[0]
    assert fii.font is None
    await pr.loadFonts()
    fii = pr.fonts[0]
    assert fii.font.axes == {}  # simple check to see if we have a font at all
Esempio n. 9
0
async def test_project_loadFont():
    pr = Project()
    fontPath = getFontPath("IBMPlexSans-Regular.ttf")
    pr.addFont(fontPath, 0)
    await pr.fonts[0].load()
    with pytest.raises(TypeError):
        pr.addFont("a string", 0)
    fii = pr.fonts[0]
    assert fii.font.axes == {}  # simple check to see if we have a font at all
Esempio n. 10
0
def test_pointCollectorQuad():
    ufoPath = getFontPath("QuadTest-Regular.ufo")
    reader = UFOReader(ufoPath)
    glyphSet = reader.getGlyphSet()
    pen = PointCollector(glyphSet)
    glyphSet["a"].draw(pen)
    assert len(pen.points) == 4
    assert len(pen.tags) == 4
    assert pen.contours == [3]
    assert pen.tags == [0, 0, 0, 0]
Esempio n. 11
0
async def test_compileUFOToPath(tmpdir):
    ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo")
    ttPath = tmpdir / "test.ttf"
    output = []
    error = await compileUFOToPath(ufoPath, ttPath, output.append)
    output = "".join(output)
    assert ttPath.exists()
    assert os.stat(ttPath).st_size > 0
    assert not error
    assert output == ""
Esempio n. 12
0
def test_shape_getStylisticSetNames():
    s = HBShape.fromPath(getFontPath("IBMPlexSans-Regular.ttf"))
    ssNames = s.getStylisticSetNames()
    expected = {
        'ss01': 'simple lowercase a',
        'ss02': 'simple lowercase g',
        'ss03': 'slashed number zero',
        'ss04': 'dotted number zero',
        'ss05': 'alternate lowercase eszett'
    }
    assert expected == ssNames
Esempio n. 13
0
async def test_getGlyphRunFromTextInfo(text, expectedGlyphNames, expectedPositions):
    fontPath = getFontPath('IBMPlexSansArabic-Regular.ttf')
    numFonts, opener, getSortInfo = getOpener(fontPath)
    font = opener(fontPath, 0)
    await font.load(None)
    textInfo = TextInfo(text)
    glyphs = font.getGlyphRunFromTextInfo(textInfo)
    glyphNames = [g.name for g in glyphs]
    positions = [g.pos for g in glyphs]
    assert expectedGlyphNames == glyphNames
    assert expectedPositions == positions
Esempio n. 14
0
async def test_compileUFOToPathMultiple(tmpdir):
    ufoPaths = [
        getFontPath("MutatorSansBoldCondensed.ufo"),
        getFontPath("MutatorSansBoldWide.ufo"),
        getFontPath("MutatorSansIntermediateCondensed.ufo"),
        getFontPath("MutatorSansIntermediateWide.ufo"),
        getFontPath("MutatorSansLightCondensed.ufo"),
        getFontPath("MutatorSansLightCondensed_support.S.middle.ufo"),
        getFontPath("MutatorSansLightCondensed_support.S.wide.ufo"),
        getFontPath("MutatorSansLightCondensed_support.crossbar.ufo"),
        getFontPath("MutatorSansLightWide.ufo"),
    ]
    ttPaths = [tmpdir / (u.name + ".ttf") for u in ufoPaths]
    output = []
    coros = (compileUFOToPath(u, t, output.append)
             for u, t in zip(ufoPaths, ttPaths))
    results = await asyncio.gather(*coros)
    assert results == [None] * len(results)
    assert [(os.stat(p).st_size > 0) for p in ttPaths] == [True] * len(results)
Esempio n. 15
0
async def test_project_purgeFonts():
    pr = Project()
    fontPath1 = getFontPath("IBMPlexSans-Regular.ttf")
    pr.addFont(fontPath1, 0)
    fontPath2 = getFontPath("IBMPlexSans-Regular.otf")
    pr.addFont(fontPath2, 0)
    assert len(pr.fonts) == 2
    assert [fii.fontKey for fii in pr.fonts] == [(fontPath1, 0),
                                                 (fontPath2, 0)]
    assert [fii.identifier for fii in pr.fonts] == ["fontItem_0", "fontItem_1"]

    assert len(pr._fontLoader.fonts) == 0
    await pr.loadFonts()
    assert len(pr._fontLoader.fonts) == 2

    del pr.fonts[0]
    assert list(pr._fontLoader.fonts) == [(fontPath1, 0), (fontPath2, 0)]
    pr.purgeFonts()
    assert list(pr._fontLoader.fonts) == [(fontPath2, 0)]
    del pr.fonts[0]
    assert list(pr._fontLoader.fonts) == [(fontPath2, 0)]
    pr.purgeFonts()
    assert list(pr._fontLoader.fonts) == []
Esempio n. 16
0
def test_ufoCharacterMapping():
    ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo")
    reader = UFOReader(ufoPath)
    cmap, revCmap, anchors = fetchCharacterMappingAndAnchors(
        reader.getGlyphSet(), ufoPath)
    assert cmap[0x0041] == "A"
    assert revCmap["A"] == [0x0041]
    # MutatorSansBoldWideMutated.ufo/glyphs/A_.glif contains a commented-out <unicode>
    # tag, that must not be parsed, as well as a commented-out <anchor>.
    assert 0x1234 not in cmap
    assert anchors == {
        "A": [("top", 645, 815)],
        "E": [("top", 582.5, 815)],
        "macroncmb": [("_top", 0, 815)]
    }
Esempio n. 17
0
async def test_mapGlyphsToChars():
    text = "عربي بِّ"
    fontPath = getFontPath('Amiri-Regular.ttf')
    numFonts, opener, getSortInfo = getOpener(fontPath)
    font = opener(fontPath, 0)
    await font.load(None)
    textInfo = TextInfo(text)
    glyphs = font.getGlyphRunFromTextInfo(textInfo)
    charIndices = []
    for glyphIndex in range(len(glyphs)):
        charIndices.append(glyphs.mapGlyphsToChars({glyphIndex}))
    expectedCharIndices = [{7}, {6}, {5}, {4}, {3}, {2}, {1}, {0}]
    assert expectedCharIndices == charIndices
    glyphIndices = []
    for charIndex in range(len(text)):
        glyphIndices.append(glyphs.mapCharsToGlyphs({charIndex}))
    expectedGlyphIndices = [{7}, {6}, {5}, {4}, {3}, {2}, {1}, {0}]
    assert expectedGlyphIndices == glyphIndices
Esempio n. 18
0
async def test_verticalGlyphMetricsFromUFO():
    fontPath = getFontPath('MutatorSansBoldWideMutated.ufo')
    numFonts, opener, getSortInfo = getOpener(fontPath)
    font = opener(fontPath, 0)
    await font.load(None)
    textInfo = TextInfo("ABCDE")
    textInfo.directionOverride = "TTB"
    glyphs = font.getGlyphRunFromTextInfo(textInfo)
    ax = [g.ax for g in glyphs]
    ay = [g.ay for g in glyphs]
    dx = [g.dx for g in glyphs]
    dy = [g.dy for g in glyphs]
    expectedAX = [0, 0, 0, 0, 0]
    expectedAY = [-1022, -1000, -1000, -1000, -1000]
    expectedDX = [-645, -635, -687, -658, -560]
    expectedDY = [-822, -800, -800, -800, -800]
    assert expectedAX == ax
    assert expectedAY == ay
    assert expectedDX == dx
    assert expectedDY == dy
Esempio n. 19
0
def test_pointCollector():
    ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo")
    reader = UFOReader(ufoPath)
    glyphSet = reader.getGlyphSet()
    pen = PointCollector(glyphSet)
    glyphSet["B"].draw(pen)
    assert len(pen.points) == 38
    assert len(pen.tags) == 38
    assert pen.contours == [3, 37]
    assert pen.tags[:12] == [1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1]

    pen = PointCollector(glyphSet)
    glyphSet["Aacute"].draw(pen)
    assert len(pen.points) == 20
    assert pen.contours == [3, 7, 11, 15, 19]

    pen = PointCollector(glyphSet)
    glyphSet["O"].draw(pen)
    assert len(pen.points) == 28
    assert pen.contours == [13, 27]
Esempio n. 20
0
async def test_colrV1Font():
    fontPath = getFontPath("more_samples-glyf_colr_1.ttf")
    numFonts, opener, getSortInfo = getOpener(fontPath)
    font = opener(fontPath, 0)
    await font.load(None)
    textInfo = TextInfo("c")
    glyphs = font.getGlyphRunFromTextInfo(textInfo)
    glyphNames = [g.name for g in glyphs]
    glyphDrawing, *_ = font.getGlyphDrawings(glyphNames, True)
    boundingBox = glyphDrawing.bounds
    assert (100, 0, 900, 1000) == boundingBox
    surface = CoreGraphicsPixelSurface(boundingBox)
    context = NSGraphicsContext.graphicsContextWithCGContext_flipped_(
        surface.context, False)
    savedContext = NSGraphicsContext.currentContext()
    try:
        NSGraphicsContext.setCurrentContext_(context)
        glyphDrawing.draw(glyphs.colorPalette, (0, 0, 0, 1))
    finally:
        NSGraphicsContext.setCurrentContext_(savedContext)
Esempio n. 21
0
def test_shape_latin(testString, features, expectedGlyphNames):
    s = HBShape.fromPath(getFontPath("IBMPlexSans-Regular.ttf"))
    glyphs = s.shape(testString, features=features)
    assert [g.name for g in glyphs] == expectedGlyphNames
Esempio n. 22
0
def test_sniffFontType():
    fontPath = getFontPath("IBMPlexSans-Regular.ttf")
    assert sniffFontType(fontPath) == "ttf"
Esempio n. 23
0
async def test_project_load_ttc():
    pr = Project()
    fontPath = getFontPath("MutatorSans.ttc")
    for fontPath, fontNumber, getSortInfo in iterFontNumbers(fontPath):
        pr.addFont(fontPath, fontNumber)
    await pr.loadFonts()
Esempio n. 24
0
async def test_DSFont_getOutline():
    ufoPath = getFontPath("MutatorSans.designspace")
    font = DSFont(ufoPath, 0)
    await font.load(sys.stderr.write)
    drawing, *_ = font.getGlyphDrawings(["A"])
    assert ((20, 0), (356, 700)) == drawing.path.bounds()
Esempio n. 25
0
def _getFonts(fileName):
    p = getFontPath(fileName)
    ttf = TTFont(p, lazy=True)
    return FTFont.fromPath(p), ttf.getGlyphSet()
Esempio n. 26
0
def test_shape_GlyphInfo_repr():
    s = HBShape.fromPath(getFontPath("IBMPlexSans-Regular.ttf"))
    glyphs = s.shape("a")
    assert repr(
        glyphs[0]
    ) == "GlyphInfo(gid=4, name='a', cluster=0, dx=0, dy=0, ax=534, ay=0)"