Home | History | Annotate | Download | only in pens
      1 from __future__ import print_function, division, absolute_import
      2 from fontTools.misc.py23 import *
      3 
      4 import os
      5 import unittest
      6 import struct
      7 
      8 from fontTools import ttLib
      9 from fontTools.misc.testTools import TestCase
     10 from fontTools.pens.ttGlyphPen import TTGlyphPen, MAX_F2DOT14
     11 
     12 
     13 class TTGlyphPenTest(TestCase):
     14 
     15     def runEndToEnd(self, filename):
     16         font = ttLib.TTFont()
     17         ttx_path = os.path.join(
     18             os.path.abspath(os.path.dirname(os.path.realpath(__file__))),
     19             '..', 'ttLib', 'data', filename)
     20         font.importXML(ttx_path)
     21 
     22         glyphSet = font.getGlyphSet()
     23         glyfTable = font['glyf']
     24         pen = TTGlyphPen(font.getGlyphSet())
     25 
     26         for name in font.getGlyphOrder():
     27             oldGlyph = glyphSet[name]
     28             oldGlyph.draw(pen)
     29             oldGlyph = oldGlyph._glyph
     30             newGlyph = pen.glyph()
     31 
     32             if hasattr(oldGlyph, 'program'):
     33                 newGlyph.program = oldGlyph.program
     34 
     35             self.assertEqual(
     36                 oldGlyph.compile(glyfTable), newGlyph.compile(glyfTable))
     37 
     38     def test_e2e_linesAndSimpleComponents(self):
     39         self.runEndToEnd('TestTTF-Regular.ttx')
     40 
     41     def test_e2e_curvesAndComponentTransforms(self):
     42         self.runEndToEnd('TestTTFComplex-Regular.ttx')
     43 
     44     def test_moveTo_errorWithinContour(self):
     45         pen = TTGlyphPen(None)
     46         pen.moveTo((0, 0))
     47         with self.assertRaises(AssertionError):
     48             pen.moveTo((1, 0))
     49 
     50     def test_closePath_ignoresAnchors(self):
     51         pen = TTGlyphPen(None)
     52         pen.moveTo((0, 0))
     53         pen.closePath()
     54         self.assertFalse(pen.points)
     55         self.assertFalse(pen.types)
     56         self.assertFalse(pen.endPts)
     57 
     58     def test_endPath_sameAsClosePath(self):
     59         pen = TTGlyphPen(None)
     60 
     61         pen.moveTo((0, 0))
     62         pen.lineTo((0, 1))
     63         pen.lineTo((1, 0))
     64         pen.closePath()
     65         closePathGlyph = pen.glyph()
     66 
     67         pen.moveTo((0, 0))
     68         pen.lineTo((0, 1))
     69         pen.lineTo((1, 0))
     70         pen.endPath()
     71         endPathGlyph = pen.glyph()
     72 
     73         self.assertEqual(closePathGlyph, endPathGlyph)
     74 
     75     def test_glyph_errorOnUnendedContour(self):
     76         pen = TTGlyphPen(None)
     77         pen.moveTo((0, 0))
     78         with self.assertRaises(AssertionError):
     79             pen.glyph()
     80 
     81     def test_glyph_decomposes(self):
     82         componentName = 'a'
     83         glyphSet = {}
     84         pen = TTGlyphPen(glyphSet)
     85 
     86         pen.moveTo((0, 0))
     87         pen.lineTo((0, 1))
     88         pen.lineTo((1, 0))
     89         pen.closePath()
     90         glyphSet[componentName] = _TestGlyph(pen.glyph())
     91 
     92         pen.moveTo((0, 0))
     93         pen.lineTo((0, 1))
     94         pen.lineTo((1, 0))
     95         pen.closePath()
     96         pen.addComponent(componentName, (1, 0, 0, 1, 2, 0))
     97         pen.addComponent("missing", (1, 0, 0, 1, 0, 0))  # skipped
     98         compositeGlyph = pen.glyph()
     99 
    100         pen.moveTo((0, 0))
    101         pen.lineTo((0, 1))
    102         pen.lineTo((1, 0))
    103         pen.closePath()
    104         pen.moveTo((2, 0))
    105         pen.lineTo((2, 1))
    106         pen.lineTo((3, 0))
    107         pen.closePath()
    108         plainGlyph = pen.glyph()
    109 
    110         self.assertEqual(plainGlyph, compositeGlyph)
    111 
    112     def test_remove_extra_move_points(self):
    113         pen = TTGlyphPen(None)
    114         pen.moveTo((0, 0))
    115         pen.lineTo((100, 0))
    116         pen.qCurveTo((100, 50), (50, 100), (0, 0))
    117         pen.closePath()
    118         self.assertEqual(len(pen.points), 4)
    119         self.assertEqual(pen.points[0], (0, 0))
    120 
    121     def test_keep_move_point(self):
    122         pen = TTGlyphPen(None)
    123         pen.moveTo((0, 0))
    124         pen.lineTo((100, 0))
    125         pen.qCurveTo((100, 50), (50, 100), (30, 30))
    126         # when last and move pts are different, closePath() implies a lineTo
    127         pen.closePath()
    128         self.assertEqual(len(pen.points), 5)
    129         self.assertEqual(pen.points[0], (0, 0))
    130 
    131     def test_keep_duplicate_end_point(self):
    132         pen = TTGlyphPen(None)
    133         pen.moveTo((0, 0))
    134         pen.lineTo((100, 0))
    135         pen.qCurveTo((100, 50), (50, 100), (0, 0))
    136         pen.lineTo((0, 0))  # the duplicate point is not removed
    137         pen.closePath()
    138         self.assertEqual(len(pen.points), 5)
    139         self.assertEqual(pen.points[0], (0, 0))
    140 
    141     def test_within_range_component_transform(self):
    142         componentName = 'a'
    143         glyphSet = {}
    144         pen = TTGlyphPen(glyphSet)
    145 
    146         pen.moveTo((0, 0))
    147         pen.lineTo((0, 1))
    148         pen.lineTo((1, 0))
    149         pen.closePath()
    150         glyphSet[componentName] = _TestGlyph(pen.glyph())
    151 
    152         pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
    153         pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
    154         compositeGlyph = pen.glyph()
    155 
    156         pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
    157         pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
    158         expectedGlyph = pen.glyph()
    159 
    160         self.assertEqual(expectedGlyph, compositeGlyph)
    161 
    162     def test_clamp_to_almost_2_component_transform(self):
    163         componentName = 'a'
    164         glyphSet = {}
    165         pen = TTGlyphPen(glyphSet)
    166 
    167         pen.moveTo((0, 0))
    168         pen.lineTo((0, 1))
    169         pen.lineTo((1, 0))
    170         pen.closePath()
    171         glyphSet[componentName] = _TestGlyph(pen.glyph())
    172 
    173         pen.addComponent(componentName, (1.99999, 0, 0, 1, 0, 0))
    174         pen.addComponent(componentName, (1, 2, 0, 1, 0, 0))
    175         pen.addComponent(componentName, (1, 0, 2, 1, 0, 0))
    176         pen.addComponent(componentName, (1, 0, 0, 2, 0, 0))
    177         pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
    178         compositeGlyph = pen.glyph()
    179 
    180         almost2 = MAX_F2DOT14  # 0b1.11111111111111
    181         pen.addComponent(componentName, (almost2, 0, 0, 1, 0, 0))
    182         pen.addComponent(componentName, (1, almost2, 0, 1, 0, 0))
    183         pen.addComponent(componentName, (1, 0, almost2, 1, 0, 0))
    184         pen.addComponent(componentName, (1, 0, 0, almost2, 0, 0))
    185         pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
    186         expectedGlyph = pen.glyph()
    187 
    188         self.assertEqual(expectedGlyph, compositeGlyph)
    189 
    190     def test_out_of_range_transform_decomposed(self):
    191         componentName = 'a'
    192         glyphSet = {}
    193         pen = TTGlyphPen(glyphSet)
    194 
    195         pen.moveTo((0, 0))
    196         pen.lineTo((0, 1))
    197         pen.lineTo((1, 0))
    198         pen.closePath()
    199         glyphSet[componentName] = _TestGlyph(pen.glyph())
    200 
    201         pen.addComponent(componentName, (3, 0, 0, 2, 0, 0))
    202         pen.addComponent(componentName, (1, 0, 0, 1, -1, 2))
    203         pen.addComponent(componentName, (2, 0, 0, -3, 0, 0))
    204         compositeGlyph = pen.glyph()
    205 
    206         pen.moveTo((0, 0))
    207         pen.lineTo((0, 2))
    208         pen.lineTo((3, 0))
    209         pen.closePath()
    210         pen.moveTo((-1, 2))
    211         pen.lineTo((-1, 3))
    212         pen.lineTo((0, 2))
    213         pen.closePath()
    214         pen.moveTo((0, 0))
    215         pen.lineTo((0, -3))
    216         pen.lineTo((2, 0))
    217         pen.closePath()
    218         expectedGlyph = pen.glyph()
    219 
    220         self.assertEqual(expectedGlyph, compositeGlyph)
    221 
    222     def test_no_handle_overflowing_transform(self):
    223         componentName = 'a'
    224         glyphSet = {}
    225         pen = TTGlyphPen(glyphSet, handleOverflowingTransforms=False)
    226 
    227         pen.moveTo((0, 0))
    228         pen.lineTo((0, 1))
    229         pen.lineTo((1, 0))
    230         pen.closePath()
    231         baseGlyph = pen.glyph()
    232         glyphSet[componentName] = _TestGlyph(baseGlyph)
    233 
    234         pen.addComponent(componentName, (3, 0, 0, 1, 0, 0))
    235         compositeGlyph = pen.glyph()
    236 
    237         self.assertEqual(compositeGlyph.components[0].transform,
    238                          ((3, 0), (0, 1)))
    239 
    240         with self.assertRaises(struct.error):
    241             compositeGlyph.compile({'a': baseGlyph})
    242 
    243 
    244 class _TestGlyph(object):
    245     def __init__(self, glyph):
    246         self.coordinates = glyph.coordinates
    247 
    248     def draw(self, pen):
    249         pen.moveTo(self.coordinates[0])
    250         for point in self.coordinates[1:]:
    251             pen.lineTo(point)
    252         pen.closePath()
    253 
    254 
    255 if __name__ == '__main__':
    256     import sys
    257     sys.exit(unittest.main())
    258