def test_clamp_to_almost_2_component_transform(self): componentName = "a" glyphSet = {} pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() glyphSet[componentName] = _TestGlyph(pen.glyph()) pen.addComponent(componentName, (1.99999, 0, 0, 1, 0, 0)) pen.addComponent(componentName, (1, 2, 0, 1, 0, 0)) pen.addComponent(componentName, (1, 0, 2, 1, 0, 0)) pen.addComponent(componentName, (1, 0, 0, 2, 0, 0)) pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0)) compositeGlyph = pen.glyph() almost2 = MAX_F2DOT14 # 0b1.11111111111111 pen.addComponent(componentName, (almost2, 0, 0, 1, 0, 0)) pen.addComponent(componentName, (1, almost2, 0, 1, 0, 0)) pen.addComponent(componentName, (1, 0, almost2, 1, 0, 0)) pen.addComponent(componentName, (1, 0, 0, almost2, 0, 0)) pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0)) expectedGlyph = pen.glyph() assert expectedGlyph == compositeGlyph
def test_keep_duplicate_end_point(self): pen = TTGlyphPointPen(None) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((100, 0), "line") pen.addPoint((100, 50)) pen.addPoint((50, 100)) pen.addPoint((0, 0), "qcurve") pen.addPoint((0, 0), "line") # the duplicate point is not removed pen.endPath() assert len(pen.points) == 6 assert pen.points[0] == (0, 0)
def test_glyph_simple(self): pen = TTGlyphPointPen(None) pen.beginPath() pen.addPoint((50, 0), "line") pen.addPoint((450, 0), "line") pen.addPoint((450, 700), "line") pen.addPoint((50, 700), "line") pen.endPath() glyph = pen.glyph() assert glyph.numberOfContours == 1 assert glyph.endPtsOfContours == [3]
def estimateCOLRv1BoundingBoxes(vcFont, ttFont, neutralOnly): from fontTools.pens.ttGlyphPen import TTGlyphPointPen from fontTools.pens.boundsPen import ControlBoundsPen locations = [{}] if not neutralOnly: for axis in ttFont["fvar"].axes: if axis.flags & 0x0001: # hidden axis continue values = {0} if axis.minValue < axis.defaultValue: values.add(-1) if axis.defaultValue < axis.maxValue: values.add(1) locations = [ dictUpdate(loc, axis.axisTag, v) for loc in locations for v in sorted(values) ] glyfTable = ttFont["glyf"] gvarTable = ttFont["gvar"] hmtxTable = ttFont["hmtx"] # TODO: fix tsb if we have "vmtx" for glyphName in sorted(vcFont.keys()): glyph = vcFont[glyphName] if not glyph.components or not glyph.outline.isEmpty(): continue # calculate the bounding box that would fit on all locations bpen = ControlBoundsPen(None) for loc in locations: vcFont.drawGlyph(bpen, glyphName, loc) gvarTable.variations.pop(glyphName, None) pen = TTGlyphPointPen(None) if bpen.bounds is not None: bounds = intRect(bpen.bounds) for pt in [bounds[:2], bounds[2:]]: pen.beginPath() pen.addPoint(pt, segmentType="line") pen.endPath() glyfTable[glyphName] = pen.glyph() adv, lsb = hmtxTable.metrics[glyphName] hmtxTable.metrics[glyphName] = adv, bounds[0]
def test_no_handle_overflowing_transform(self): componentName = "a" glyphSet = {} pen = TTGlyphPointPen(glyphSet, handleOverflowingTransforms=False) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() baseGlyph = pen.glyph() glyphSet[componentName] = _TestGlyph(baseGlyph) pen.addComponent(componentName, (3, 0, 0, 1, 0, 0)) compositeGlyph = pen.glyph() assert compositeGlyph.components[0].transform == ((3, 0), (0, 1)) with pytest.raises(struct.error): compositeGlyph.compile({"a": baseGlyph})
def test_within_range_component_transform(self): componentName = "a" glyphSet = {} pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() glyphSet[componentName] = _TestGlyph(pen.glyph()) pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0)) pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0)) compositeGlyph = pen.glyph() pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0)) pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0)) expectedGlyph = pen.glyph() assert expectedGlyph == compositeGlyph
def test_round_float_coordinates_and_component_offsets(self): glyphSet = {} pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((367.6, 0), "line") pen.endPath() simpleGlyph = pen.glyph() simpleGlyph.recalcBounds(glyphSet) self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1)) componentName = "a" glyphSet[componentName] = simpleGlyph pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0)) compositeGlyph = pen.glyph() compositeGlyph.recalcBounds(glyphSet) self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1))
def test_open_path_starting_with_move(self): # when a contour starts with a 'move' point, it signifies the beginnig # of an open contour. # https://unifiedfontobject.org/versions/ufo3/glyphs/glif/#point-types pen1 = TTGlyphPointPen(None) pen1.beginPath() pen1.addPoint((0, 0), "move") # contour is open pen1.addPoint((10, 10), "line") pen1.addPoint((20, 20)) pen1.addPoint((20, 0), "qcurve") pen1.endPath() pen2 = TTGlyphPointPen(None) pen2.beginPath() pen2.addPoint((0, 0), "line") # contour is closed pen2.addPoint((10, 10), "line") pen2.addPoint((20, 20)) pen2.addPoint((20, 0), "qcurve") pen2.endPath() # Since TrueType contours are always implicitly closed, the pen will # interpret both these paths as equivalent assert pen1.points == pen2.points == [(0, 0), (10, 10), (20, 20), (20, 0)] assert pen1.types == pen2.types == [1, 1, 0, 1]
def test_scaled_component_bounds(self): glyphSet = {} pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((-231, 939), "line") pen.addPoint((-55, 939), "line") pen.addPoint((-55, 745), "line") pen.addPoint((-231, 745), "line") pen.endPath() glyphSet["gravecomb"] = pen.glyph() pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((-278, 939), "line") pen.addPoint((8, 939), "line") pen.addPoint((8, 745), "line") pen.addPoint((-278, 745), "line") pen.endPath() glyphSet["circumflexcomb"] = pen.glyph() pen = TTGlyphPointPen(glyphSet) pen.addComponent("circumflexcomb", (1, 0, 0, 1, 0, 0)) pen.addComponent("gravecomb", (0.9, 0, 0, 0.9, 198, 180)) glyphSet["uni0302_uni0300"] = uni0302_uni0300 = pen.glyph() uni0302_uni0300.recalcBounds(glyphSet) self.assertGlyphBoundsEqual(uni0302_uni0300, (-278, 745, 148, 1025))
def test_out_of_range_transform_decomposed(self): componentName = "a" glyphSet = {} pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() glyphSet[componentName] = _TestGlyph(pen.glyph()) pen.addComponent(componentName, (3, 0, 0, 2, 0, 0)) pen.addComponent(componentName, (1, 0, 0, 1, -1, 2)) pen.addComponent(componentName, (2, 0, 0, -3, 0, 0)) compositeGlyph = pen.glyph() pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 2), "line") pen.addPoint((3, 0), "line") pen.endPath() pen.beginPath() pen.addPoint((-1, 2), "line") pen.addPoint((-1, 3), "line") pen.addPoint((0, 2), "line") pen.endPath() pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, -3), "line") pen.addPoint((2, 0), "line") pen.endPath() expectedGlyph = pen.glyph() assert expectedGlyph == compositeGlyph
def test_glyph_decomposes(self): componentName = "a" glyphSet = {} pen = TTGlyphPointPen(glyphSet) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() glyphSet[componentName] = _TestGlyph(pen.glyph()) pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() pen.addComponent(componentName, (1, 0, 0, 1, 2, 0)) pen.addComponent("missing", (1, 0, 0, 1, 0, 0)) # skipped compositeGlyph = pen.glyph() pen.beginPath() pen.addPoint((0, 0), "line") pen.addPoint((0, 1), "line") pen.addPoint((1, 0), "line") pen.endPath() pen.beginPath() pen.addPoint((2, 0), "line") pen.addPoint((2, 1), "line") pen.addPoint((3, 0), "line") pen.endPath() plainGlyph = pen.glyph() assert plainGlyph == compositeGlyph
def test_glyph_errorOnUnendedContour(self): pen = TTGlyphPointPen(None) pen.beginPath() pen.addPoint((0, 0)) with pytest.raises(PenError): pen.glyph()
def test_beginPath_beginPathOnOpenPath(self): pen = TTGlyphPointPen(None) pen.beginPath() pen.addPoint((0, 0)) with pytest.raises(PenError): pen.beginPath()
def test_addPoint_errorOnCurve(self): pen = TTGlyphPointPen(None) pen.beginPath() with pytest.raises(NotImplementedError): pen.addPoint((0, 0), "curve")