We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
TTFont.getGlyphSet() returning _TTVarGlyphSet where type hints/typechecker expect _TTGlyphSet
the new `_TTVarGlyphSet` (#2738) that is returned from `TTFont.getGlyphSet()` is not a subclass of the old `_TTGlyphSet`, and neither is the `_TTVarGlyphGlyf` that it contains a subclass of the old `_TTGlyph`.
We have some internal code that uses type hints and is typechecked using pytype, which breaks with the latest fonttools 4.36.0 following the above change.

```
bad option 'fontTools.ttLib.ttGlyphSet._TTVarGlyphGlyf' in return type [bad-return-type]
           Expected: fontTools.ttLib.ttGlyphSet._TTGlyph
```

I think we should revise the class hierarchy of these glyphset/glyph objects and make sure that we continue to return a `_TTGlyphSet` that contains generic `_TTGlyph` objects and work around their respective differences inside subclasses.
I think it's doable.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `Lib/fontTools/ttLib/ttGlyphSet.py`
Content:
```
1 """GlyphSets returned by a TTFont."""
2 
3 from fontTools.misc.fixedTools import otRound
4 from copy import copy
5 
6 class _TTGlyphSet(object):
7 
8 	"""Generic dict-like GlyphSet class that pulls metrics from hmtx and
9 	glyph shape from TrueType or CFF.
10 	"""
11 
12 	def __init__(self, ttFont, glyphs, glyphType):
13 		"""Construct a new glyphset.
14 
15 		Args:
16 			font (TTFont): The font object (used to get metrics).
17 			glyphs (dict): A dictionary mapping glyph names to ``_TTGlyph`` objects.
18 			glyphType (class): Either ``_TTGlyphCFF`` or ``_TTGlyphGlyf``.
19 		"""
20 		self._glyphs = glyphs
21 		self._hmtx = ttFont['hmtx']
22 		self._vmtx = ttFont['vmtx'] if 'vmtx' in ttFont else None
23 		self._glyphType = glyphType
24 
25 	def keys(self):
26 		return list(self._glyphs.keys())
27 
28 	def has_key(self, glyphName):
29 		return glyphName in self._glyphs
30 
31 	__contains__ = has_key
32 
33 	def __getitem__(self, glyphName):
34 		horizontalMetrics = self._hmtx[glyphName]
35 		verticalMetrics = self._vmtx[glyphName] if self._vmtx else None
36 		return self._glyphType(
37 			self, self._glyphs[glyphName], horizontalMetrics, verticalMetrics)
38 
39 	def __len__(self):
40 		return len(self._glyphs)
41 
42 	def get(self, glyphName, default=None):
43 		try:
44 			return self[glyphName]
45 		except KeyError:
46 			return default
47 
48 class _TTGlyph(object):
49 
50 	"""Wrapper for a TrueType glyph that supports the Pen protocol, meaning
51 	that it has .draw() and .drawPoints() methods that take a pen object as
52 	their only argument. Additionally there are 'width' and 'lsb' attributes,
53 	read from the 'hmtx' table.
54 
55 	If the font contains a 'vmtx' table, there will also be 'height' and 'tsb'
56 	attributes.
57 	"""
58 
59 	def __init__(self, glyphset, glyph, horizontalMetrics, verticalMetrics=None):
60 		"""Construct a new _TTGlyph.
61 
62 		Args:
63 			glyphset (_TTGlyphSet): A glyphset object used to resolve components.
64 			glyph (ttLib.tables._g_l_y_f.Glyph): The glyph object.
65 			horizontalMetrics (int, int): The glyph's width and left sidebearing.
66 		"""
67 		self._glyphset = glyphset
68 		self._glyph = glyph
69 		self.width, self.lsb = horizontalMetrics
70 		if verticalMetrics:
71 			self.height, self.tsb = verticalMetrics
72 		else:
73 			self.height, self.tsb = None, None
74 
75 	def draw(self, pen):
76 		"""Draw the glyph onto ``pen``. See fontTools.pens.basePen for details
77 		how that works.
78 		"""
79 		self._glyph.draw(pen)
80 
81 	def drawPoints(self, pen):
82 		# drawPoints is only implemented for _TTGlyphGlyf at this time.
83 		raise NotImplementedError()
84 
85 class _TTGlyphCFF(_TTGlyph):
86 	pass
87 
88 class _TTGlyphGlyf(_TTGlyph):
89 
90 	def draw(self, pen):
91 		"""Draw the glyph onto Pen. See fontTools.pens.basePen for details
92 		how that works.
93 		"""
94 		glyfTable = self._glyphset._glyphs
95 		glyph = self._glyph
96 		offset = self.lsb - glyph.xMin if hasattr(glyph, "xMin") else 0
97 		glyph.draw(pen, glyfTable, offset)
98 
99 	def drawPoints(self, pen):
100 		"""Draw the glyph onto PointPen. See fontTools.pens.pointPen
101 		for details how that works.
102 		"""
103 		glyfTable = self._glyphset._glyphs
104 		glyph = self._glyph
105 		offset = self.lsb - glyph.xMin if hasattr(glyph, "xMin") else 0
106 		glyph.drawPoints(pen, glyfTable, offset)
107 
108 
109 
110 class _TTVarGlyphSet(object):
111 
112 	def __init__(self, font, location, normalized=False):
113 		from fontTools.varLib.models import normalizeLocation, piecewiseLinearMap
114 		self._ttFont = font
115 		if not normalized:
116 			axes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in font['fvar'].axes}
117 			location = normalizeLocation(location, axes)
118 			if 'avar' in font:
119 				avar = font['avar']
120 				avarSegments = avar.segments
121 				new_location = {}
122 				for axis_tag,value in location.items():
123 					avarMapping = avarSegments.get(axis_tag, None)
124 					if avarMapping is not None:
125 						value = piecewiseLinearMap(value, avarMapping)
126 					new_location[axis_tag] = value
127 				location = new_location
128 				del new_location
129 
130 		self.location = location
131 
132 	def keys(self):
133 		return list(self._ttFont['glyf'].keys())
134 
135 	def has_key(self, glyphName):
136 		return glyphName in self._ttFont['glyf']
137 	__contains__ = has_key
138 
139 	def __getitem__(self, glyphName):
140 		return _TTVarGlyphGlyf(self._ttFont, glyphName, self.location)
141 
142 	def get(self, glyphName, default=None):
143 		try:
144 			return self[glyphName]
145 		except KeyError:
146 			return default
147 
148 def _setCoordinates(glyph, coord, glyfTable):
149 	# Handle phantom points for (left, right, top, bottom) positions.
150 	assert len(coord) >= 4
151 	if not hasattr(glyph, 'xMin'):
152 		glyph.recalcBounds(glyfTable)
153 	leftSideX = coord[-4][0]
154 	rightSideX = coord[-3][0]
155 	topSideY = coord[-2][1]
156 	bottomSideY = coord[-1][1]
157 
158 	for _ in range(4):
159 		del coord[-1]
160 
161 	if glyph.isComposite():
162 		assert len(coord) == len(glyph.components)
163 		for p,comp in zip(coord, glyph.components):
164 			if hasattr(comp, 'x'):
165 				comp.x,comp.y = p
166 	elif glyph.numberOfContours == 0:
167 		assert len(coord) == 0
168 	else:
169 		assert len(coord) == len(glyph.coordinates)
170 		glyph.coordinates = coord
171 
172 	glyph.recalcBounds(glyfTable)
173 
174 	horizontalAdvanceWidth = otRound(rightSideX - leftSideX)
175 	verticalAdvanceWidth = otRound(topSideY - bottomSideY)
176 	leftSideBearing = otRound(glyph.xMin - leftSideX)
177 	return horizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth
178 
179 
180 class _TTVarGlyphGlyf(object):
181 
182 	def __init__(self, ttFont, glyphName, location):
183 		self._ttFont = ttFont
184 		self._glyphName = glyphName
185 		self._location = location
186 		self.width = None # draw fills it in
187 
188 	def draw(self, pen):
189 		from fontTools.varLib.iup import iup_delta
190 		from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
191 		from fontTools.varLib.models import supportScalar
192 
193 		glyf = self._ttFont['glyf']
194 		hMetrics = self._ttFont['hmtx'].metrics
195 		vMetrics = getattr(self._ttFont.get('vmtx'), 'metrics', None)
196 
197 		variations = self._ttFont['gvar'].variations[self._glyphName]
198 		coordinates, _ = glyf._getCoordinatesAndControls(self._glyphName, hMetrics, vMetrics)
199 		origCoords, endPts = None, None
200 		for var in variations:
201 			scalar = supportScalar(self._location, var.axes)
202 			if not scalar:
203 				continue
204 			delta = var.coordinates
205 			if None in delta:
206 				if origCoords is None:
207 					origCoords,control = glyf._getCoordinatesAndControls(self._glyphName, hMetrics, vMetrics)
208 					endPts = control[1] if control[0] >= 1 else list(range(len(control[1])))
209 				delta = iup_delta(delta, origCoords, endPts)
210 			coordinates += GlyphCoordinates(delta) * scalar
211 
212 		glyph = copy(glyf[self._glyphName]) # Shallow copy
213 		horizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth = _setCoordinates(glyph, coordinates, glyf)
214 		self.width = horizontalAdvanceWidth
215 		self.height = verticalAdvanceWidth
216 		offset = leftSideBearing - glyph.xMin if hasattr(glyph, "xMin") else 0
217 		glyph.draw(pen, glyf, offset)
218
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/Lib/fontTools/ttLib/ttGlyphSet.py b/Lib/fontTools/ttLib/ttGlyphSet.py
--- a/Lib/fontTools/ttLib/ttGlyphSet.py
+++ b/Lib/fontTools/ttLib/ttGlyphSet.py
@@ -107,19 +107,22 @@
 
 
 
-class _TTVarGlyphSet(object):
+class _TTVarGlyphSet(_TTGlyphSet):
 
 	def __init__(self, font, location, normalized=False):
-		from fontTools.varLib.models import normalizeLocation, piecewiseLinearMap
 		self._ttFont = font
+		self._glyphs = font['glyf']
+
 		if not normalized:
+			from fontTools.varLib.models import normalizeLocation, piecewiseLinearMap
+
 			axes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in font['fvar'].axes}
 			location = normalizeLocation(location, axes)
 			if 'avar' in font:
 				avar = font['avar']
 				avarSegments = avar.segments
 				new_location = {}
-				for axis_tag,value in location.items():
+				for axis_tag, value in location.items():
 					avarMapping = avarSegments.get(axis_tag, None)
 					if avarMapping is not None:
 						value = piecewiseLinearMap(value, avarMapping)
@@ -129,21 +132,11 @@
 
 		self.location = location
 
-	def keys(self):
-		return list(self._ttFont['glyf'].keys())
-
-	def has_key(self, glyphName):
-		return glyphName in self._ttFont['glyf']
-	__contains__ = has_key
-
 	def __getitem__(self, glyphName):
+		if glyphName not in self._glyphs:
+			raise KeyError(glyphName)
 		return _TTVarGlyphGlyf(self._ttFont, glyphName, self.location)
 
-	def get(self, glyphName, default=None):
-		try:
-			return self[glyphName]
-		except KeyError:
-			return default
 
 def _setCoordinates(glyph, coord, glyfTable):
 	# Handle phantom points for (left, right, top, bottom) positions.
@@ -174,16 +167,25 @@
 	horizontalAdvanceWidth = otRound(rightSideX - leftSideX)
 	verticalAdvanceWidth = otRound(topSideY - bottomSideY)
 	leftSideBearing = otRound(glyph.xMin - leftSideX)
-	return horizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth
+	topSideBearing = otRound(topSideY - glyph.yMax)
+	return (
+		horizontalAdvanceWidth,
+		leftSideBearing,
+		verticalAdvanceWidth,
+		topSideBearing,
+	)
 
 
-class _TTVarGlyphGlyf(object):
-
+class _TTVarGlyph(_TTGlyph):
 	def __init__(self, ttFont, glyphName, location):
 		self._ttFont = ttFont
 		self._glyphName = glyphName
 		self._location = location
-		self.width = None # draw fills it in
+		# draw() fills these in
+		self.width = self.height = self.lsb = self.tsb = None
+
+
+class _TTVarGlyphGlyf(_TTVarGlyph):
 
 	def draw(self, pen):
 		from fontTools.varLib.iup import iup_delta
@@ -210,8 +212,10 @@
 			coordinates += GlyphCoordinates(delta) * scalar
 
 		glyph = copy(glyf[self._glyphName]) # Shallow copy
-		horizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth = _setCoordinates(glyph, coordinates, glyf)
-		self.width = horizontalAdvanceWidth
-		self.height = verticalAdvanceWidth
-		offset = leftSideBearing - glyph.xMin if hasattr(glyph, "xMin") else 0
+		width, lsb, height, tsb = _setCoordinates(glyph, coordinates, glyf)
+		self.width = width
+		self.lsb = lsb
+		self.height = height
+		self.tsb = tsb
+		offset = lsb - glyph.xMin if hasattr(glyph, "xMin") else 0
 		glyph.draw(pen, glyf, offset)

{"golden_diff": "diff --git a/Lib/fontTools/ttLib/ttGlyphSet.py b/Lib/fontTools/ttLib/ttGlyphSet.py\n--- a/Lib/fontTools/ttLib/ttGlyphSet.py\n+++ b/Lib/fontTools/ttLib/ttGlyphSet.py\n@@ -107,19 +107,22 @@\n \n \n \n-class _TTVarGlyphSet(object):\n+class _TTVarGlyphSet(_TTGlyphSet):\n \n \tdef __init__(self, font, location, normalized=False):\n-\t\tfrom fontTools.varLib.models import normalizeLocation, piecewiseLinearMap\n \t\tself._ttFont = font\n+\t\tself._glyphs = font['glyf']\n+\n \t\tif not normalized:\n+\t\t\tfrom fontTools.varLib.models import normalizeLocation, piecewiseLinearMap\n+\n \t\t\taxes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in font['fvar'].axes}\n \t\t\tlocation = normalizeLocation(location, axes)\n \t\t\tif 'avar' in font:\n \t\t\t\tavar = font['avar']\n \t\t\t\tavarSegments = avar.segments\n \t\t\t\tnew_location = {}\n-\t\t\t\tfor axis_tag,value in location.items():\n+\t\t\t\tfor axis_tag, value in location.items():\n \t\t\t\t\tavarMapping = avarSegments.get(axis_tag, None)\n \t\t\t\t\tif avarMapping is not None:\n \t\t\t\t\t\tvalue = piecewiseLinearMap(value, avarMapping)\n@@ -129,21 +132,11 @@\n \n \t\tself.location = location\n \n-\tdef keys(self):\n-\t\treturn list(self._ttFont['glyf'].keys())\n-\n-\tdef has_key(self, glyphName):\n-\t\treturn glyphName in self._ttFont['glyf']\n-\t__contains__ = has_key\n-\n \tdef __getitem__(self, glyphName):\n+\t\tif glyphName not in self._glyphs:\n+\t\t\traise KeyError(glyphName)\n \t\treturn _TTVarGlyphGlyf(self._ttFont, glyphName, self.location)\n \n-\tdef get(self, glyphName, default=None):\n-\t\ttry:\n-\t\t\treturn self[glyphName]\n-\t\texcept KeyError:\n-\t\t\treturn default\n \n def _setCoordinates(glyph, coord, glyfTable):\n \t# Handle phantom points for (left, right, top, bottom) positions.\n@@ -174,16 +167,25 @@\n \thorizontalAdvanceWidth = otRound(rightSideX - leftSideX)\n \tverticalAdvanceWidth = otRound(topSideY - bottomSideY)\n \tleftSideBearing = otRound(glyph.xMin - leftSideX)\n-\treturn horizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth\n+\ttopSideBearing = otRound(topSideY - glyph.yMax)\n+\treturn (\n+\t\thorizontalAdvanceWidth,\n+\t\tleftSideBearing,\n+\t\tverticalAdvanceWidth,\n+\t\ttopSideBearing,\n+\t)\n \n \n-class _TTVarGlyphGlyf(object):\n-\n+class _TTVarGlyph(_TTGlyph):\n \tdef __init__(self, ttFont, glyphName, location):\n \t\tself._ttFont = ttFont\n \t\tself._glyphName = glyphName\n \t\tself._location = location\n-\t\tself.width = None # draw fills it in\n+\t\t# draw() fills these in\n+\t\tself.width = self.height = self.lsb = self.tsb = None\n+\n+\n+class _TTVarGlyphGlyf(_TTVarGlyph):\n \n \tdef draw(self, pen):\n \t\tfrom fontTools.varLib.iup import iup_delta\n@@ -210,8 +212,10 @@\n \t\t\tcoordinates += GlyphCoordinates(delta) * scalar\n \n \t\tglyph = copy(glyf[self._glyphName]) # Shallow copy\n-\t\thorizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth = _setCoordinates(glyph, coordinates, glyf)\n-\t\tself.width = horizontalAdvanceWidth\n-\t\tself.height = verticalAdvanceWidth\n-\t\toffset = leftSideBearing - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n+\t\twidth, lsb, height, tsb = _setCoordinates(glyph, coordinates, glyf)\n+\t\tself.width = width\n+\t\tself.lsb = lsb\n+\t\tself.height = height\n+\t\tself.tsb = tsb\n+\t\toffset = lsb - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n \t\tglyph.draw(pen, glyf, offset)\n", "issue": "TTFont.getGlyphSet() returning _TTVarGlyphSet where type hints/typechecker expect _TTGlyphSet\nthe new `_TTVarGlyphSet` (#2738) that is returned from `TTFont.getGlyphSet()` is not a subclass of the old `_TTGlyphSet`, and neither is the `_TTVarGlyphGlyf` that it contains a subclass of the old `_TTGlyph`.\r\nWe have some internal code that uses type hints and is typechecked using pytype, which breaks with the latest fonttools 4.36.0 following the above change.\r\n\r\n```\r\nbad option 'fontTools.ttLib.ttGlyphSet._TTVarGlyphGlyf' in return type [bad-return-type]\r\n           Expected: fontTools.ttLib.ttGlyphSet._TTGlyph\r\n```\r\n\r\nI think we should revise the class hierarchy of these glyphset/glyph objects and make sure that we continue to return a `_TTGlyphSet` that contains generic `_TTGlyph` objects and work around their respective differences inside subclasses.\r\nI think it's doable.\n", "before_files": [{"content": "\"\"\"GlyphSets returned by a TTFont.\"\"\"\n\nfrom fontTools.misc.fixedTools import otRound\nfrom copy import copy\n\nclass _TTGlyphSet(object):\n\n\t\"\"\"Generic dict-like GlyphSet class that pulls metrics from hmtx and\n\tglyph shape from TrueType or CFF.\n\t\"\"\"\n\n\tdef __init__(self, ttFont, glyphs, glyphType):\n\t\t\"\"\"Construct a new glyphset.\n\n\t\tArgs:\n\t\t\tfont (TTFont): The font object (used to get metrics).\n\t\t\tglyphs (dict): A dictionary mapping glyph names to ``_TTGlyph`` objects.\n\t\t\tglyphType (class): Either ``_TTGlyphCFF`` or ``_TTGlyphGlyf``.\n\t\t\"\"\"\n\t\tself._glyphs = glyphs\n\t\tself._hmtx = ttFont['hmtx']\n\t\tself._vmtx = ttFont['vmtx'] if 'vmtx' in ttFont else None\n\t\tself._glyphType = glyphType\n\n\tdef keys(self):\n\t\treturn list(self._glyphs.keys())\n\n\tdef has_key(self, glyphName):\n\t\treturn glyphName in self._glyphs\n\n\t__contains__ = has_key\n\n\tdef __getitem__(self, glyphName):\n\t\thorizontalMetrics = self._hmtx[glyphName]\n\t\tverticalMetrics = self._vmtx[glyphName] if self._vmtx else None\n\t\treturn self._glyphType(\n\t\t\tself, self._glyphs[glyphName], horizontalMetrics, verticalMetrics)\n\n\tdef __len__(self):\n\t\treturn len(self._glyphs)\n\n\tdef get(self, glyphName, default=None):\n\t\ttry:\n\t\t\treturn self[glyphName]\n\t\texcept KeyError:\n\t\t\treturn default\n\nclass _TTGlyph(object):\n\n\t\"\"\"Wrapper for a TrueType glyph that supports the Pen protocol, meaning\n\tthat it has .draw() and .drawPoints() methods that take a pen object as\n\ttheir only argument. Additionally there are 'width' and 'lsb' attributes,\n\tread from the 'hmtx' table.\n\n\tIf the font contains a 'vmtx' table, there will also be 'height' and 'tsb'\n\tattributes.\n\t\"\"\"\n\n\tdef __init__(self, glyphset, glyph, horizontalMetrics, verticalMetrics=None):\n\t\t\"\"\"Construct a new _TTGlyph.\n\n\t\tArgs:\n\t\t\tglyphset (_TTGlyphSet): A glyphset object used to resolve components.\n\t\t\tglyph (ttLib.tables._g_l_y_f.Glyph): The glyph object.\n\t\t\thorizontalMetrics (int, int): The glyph's width and left sidebearing.\n\t\t\"\"\"\n\t\tself._glyphset = glyphset\n\t\tself._glyph = glyph\n\t\tself.width, self.lsb = horizontalMetrics\n\t\tif verticalMetrics:\n\t\t\tself.height, self.tsb = verticalMetrics\n\t\telse:\n\t\t\tself.height, self.tsb = None, None\n\n\tdef draw(self, pen):\n\t\t\"\"\"Draw the glyph onto ``pen``. See fontTools.pens.basePen for details\n\t\thow that works.\n\t\t\"\"\"\n\t\tself._glyph.draw(pen)\n\n\tdef drawPoints(self, pen):\n\t\t# drawPoints is only implemented for _TTGlyphGlyf at this time.\n\t\traise NotImplementedError()\n\nclass _TTGlyphCFF(_TTGlyph):\n\tpass\n\nclass _TTGlyphGlyf(_TTGlyph):\n\n\tdef draw(self, pen):\n\t\t\"\"\"Draw the glyph onto Pen. See fontTools.pens.basePen for details\n\t\thow that works.\n\t\t\"\"\"\n\t\tglyfTable = self._glyphset._glyphs\n\t\tglyph = self._glyph\n\t\toffset = self.lsb - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n\t\tglyph.draw(pen, glyfTable, offset)\n\n\tdef drawPoints(self, pen):\n\t\t\"\"\"Draw the glyph onto PointPen. See fontTools.pens.pointPen\n\t\tfor details how that works.\n\t\t\"\"\"\n\t\tglyfTable = self._glyphset._glyphs\n\t\tglyph = self._glyph\n\t\toffset = self.lsb - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n\t\tglyph.drawPoints(pen, glyfTable, offset)\n\n\n\nclass _TTVarGlyphSet(object):\n\n\tdef __init__(self, font, location, normalized=False):\n\t\tfrom fontTools.varLib.models import normalizeLocation, piecewiseLinearMap\n\t\tself._ttFont = font\n\t\tif not normalized:\n\t\t\taxes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in font['fvar'].axes}\n\t\t\tlocation = normalizeLocation(location, axes)\n\t\t\tif 'avar' in font:\n\t\t\t\tavar = font['avar']\n\t\t\t\tavarSegments = avar.segments\n\t\t\t\tnew_location = {}\n\t\t\t\tfor axis_tag,value in location.items():\n\t\t\t\t\tavarMapping = avarSegments.get(axis_tag, None)\n\t\t\t\t\tif avarMapping is not None:\n\t\t\t\t\t\tvalue = piecewiseLinearMap(value, avarMapping)\n\t\t\t\t\tnew_location[axis_tag] = value\n\t\t\t\tlocation = new_location\n\t\t\t\tdel new_location\n\n\t\tself.location = location\n\n\tdef keys(self):\n\t\treturn list(self._ttFont['glyf'].keys())\n\n\tdef has_key(self, glyphName):\n\t\treturn glyphName in self._ttFont['glyf']\n\t__contains__ = has_key\n\n\tdef __getitem__(self, glyphName):\n\t\treturn _TTVarGlyphGlyf(self._ttFont, glyphName, self.location)\n\n\tdef get(self, glyphName, default=None):\n\t\ttry:\n\t\t\treturn self[glyphName]\n\t\texcept KeyError:\n\t\t\treturn default\n\ndef _setCoordinates(glyph, coord, glyfTable):\n\t# Handle phantom points for (left, right, top, bottom) positions.\n\tassert len(coord) >= 4\n\tif not hasattr(glyph, 'xMin'):\n\t\tglyph.recalcBounds(glyfTable)\n\tleftSideX = coord[-4][0]\n\trightSideX = coord[-3][0]\n\ttopSideY = coord[-2][1]\n\tbottomSideY = coord[-1][1]\n\n\tfor _ in range(4):\n\t\tdel coord[-1]\n\n\tif glyph.isComposite():\n\t\tassert len(coord) == len(glyph.components)\n\t\tfor p,comp in zip(coord, glyph.components):\n\t\t\tif hasattr(comp, 'x'):\n\t\t\t\tcomp.x,comp.y = p\n\telif glyph.numberOfContours == 0:\n\t\tassert len(coord) == 0\n\telse:\n\t\tassert len(coord) == len(glyph.coordinates)\n\t\tglyph.coordinates = coord\n\n\tglyph.recalcBounds(glyfTable)\n\n\thorizontalAdvanceWidth = otRound(rightSideX - leftSideX)\n\tverticalAdvanceWidth = otRound(topSideY - bottomSideY)\n\tleftSideBearing = otRound(glyph.xMin - leftSideX)\n\treturn horizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth\n\n\nclass _TTVarGlyphGlyf(object):\n\n\tdef __init__(self, ttFont, glyphName, location):\n\t\tself._ttFont = ttFont\n\t\tself._glyphName = glyphName\n\t\tself._location = location\n\t\tself.width = None # draw fills it in\n\n\tdef draw(self, pen):\n\t\tfrom fontTools.varLib.iup import iup_delta\n\t\tfrom fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates\n\t\tfrom fontTools.varLib.models import supportScalar\n\n\t\tglyf = self._ttFont['glyf']\n\t\thMetrics = self._ttFont['hmtx'].metrics\n\t\tvMetrics = getattr(self._ttFont.get('vmtx'), 'metrics', None)\n\n\t\tvariations = self._ttFont['gvar'].variations[self._glyphName]\n\t\tcoordinates, _ = glyf._getCoordinatesAndControls(self._glyphName, hMetrics, vMetrics)\n\t\torigCoords, endPts = None, None\n\t\tfor var in variations:\n\t\t\tscalar = supportScalar(self._location, var.axes)\n\t\t\tif not scalar:\n\t\t\t\tcontinue\n\t\t\tdelta = var.coordinates\n\t\t\tif None in delta:\n\t\t\t\tif origCoords is None:\n\t\t\t\t\torigCoords,control = glyf._getCoordinatesAndControls(self._glyphName, hMetrics, vMetrics)\n\t\t\t\t\tendPts = control[1] if control[0] >= 1 else list(range(len(control[1])))\n\t\t\t\tdelta = iup_delta(delta, origCoords, endPts)\n\t\t\tcoordinates += GlyphCoordinates(delta) * scalar\n\n\t\tglyph = copy(glyf[self._glyphName]) # Shallow copy\n\t\thorizontalAdvanceWidth, leftSideBearing, verticalAdvanceWidth = _setCoordinates(glyph, coordinates, glyf)\n\t\tself.width = horizontalAdvanceWidth\n\t\tself.height = verticalAdvanceWidth\n\t\toffset = leftSideBearing - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n\t\tglyph.draw(pen, glyf, offset)\n", "path": "Lib/fontTools/ttLib/ttGlyphSet.py"}], "after_files": [{"content": "\"\"\"GlyphSets returned by a TTFont.\"\"\"\n\nfrom fontTools.misc.fixedTools import otRound\nfrom copy import copy\n\nclass _TTGlyphSet(object):\n\n\t\"\"\"Generic dict-like GlyphSet class that pulls metrics from hmtx and\n\tglyph shape from TrueType or CFF.\n\t\"\"\"\n\n\tdef __init__(self, ttFont, glyphs, glyphType):\n\t\t\"\"\"Construct a new glyphset.\n\n\t\tArgs:\n\t\t\tfont (TTFont): The font object (used to get metrics).\n\t\t\tglyphs (dict): A dictionary mapping glyph names to ``_TTGlyph`` objects.\n\t\t\tglyphType (class): Either ``_TTGlyphCFF`` or ``_TTGlyphGlyf``.\n\t\t\"\"\"\n\t\tself._glyphs = glyphs\n\t\tself._hmtx = ttFont['hmtx']\n\t\tself._vmtx = ttFont['vmtx'] if 'vmtx' in ttFont else None\n\t\tself._glyphType = glyphType\n\n\tdef keys(self):\n\t\treturn list(self._glyphs.keys())\n\n\tdef has_key(self, glyphName):\n\t\treturn glyphName in self._glyphs\n\n\t__contains__ = has_key\n\n\tdef __getitem__(self, glyphName):\n\t\thorizontalMetrics = self._hmtx[glyphName]\n\t\tverticalMetrics = self._vmtx[glyphName] if self._vmtx else None\n\t\treturn self._glyphType(\n\t\t\tself, self._glyphs[glyphName], horizontalMetrics, verticalMetrics)\n\n\tdef __len__(self):\n\t\treturn len(self._glyphs)\n\n\tdef get(self, glyphName, default=None):\n\t\ttry:\n\t\t\treturn self[glyphName]\n\t\texcept KeyError:\n\t\t\treturn default\n\nclass _TTGlyph(object):\n\n\t\"\"\"Wrapper for a TrueType glyph that supports the Pen protocol, meaning\n\tthat it has .draw() and .drawPoints() methods that take a pen object as\n\ttheir only argument. Additionally there are 'width' and 'lsb' attributes,\n\tread from the 'hmtx' table.\n\n\tIf the font contains a 'vmtx' table, there will also be 'height' and 'tsb'\n\tattributes.\n\t\"\"\"\n\n\tdef __init__(self, glyphset, glyph, horizontalMetrics, verticalMetrics=None):\n\t\t\"\"\"Construct a new _TTGlyph.\n\n\t\tArgs:\n\t\t\tglyphset (_TTGlyphSet): A glyphset object used to resolve components.\n\t\t\tglyph (ttLib.tables._g_l_y_f.Glyph): The glyph object.\n\t\t\thorizontalMetrics (int, int): The glyph's width and left sidebearing.\n\t\t\"\"\"\n\t\tself._glyphset = glyphset\n\t\tself._glyph = glyph\n\t\tself.width, self.lsb = horizontalMetrics\n\t\tif verticalMetrics:\n\t\t\tself.height, self.tsb = verticalMetrics\n\t\telse:\n\t\t\tself.height, self.tsb = None, None\n\n\tdef draw(self, pen):\n\t\t\"\"\"Draw the glyph onto ``pen``. See fontTools.pens.basePen for details\n\t\thow that works.\n\t\t\"\"\"\n\t\tself._glyph.draw(pen)\n\n\tdef drawPoints(self, pen):\n\t\t# drawPoints is only implemented for _TTGlyphGlyf at this time.\n\t\traise NotImplementedError()\n\nclass _TTGlyphCFF(_TTGlyph):\n\tpass\n\nclass _TTGlyphGlyf(_TTGlyph):\n\n\tdef draw(self, pen):\n\t\t\"\"\"Draw the glyph onto Pen. See fontTools.pens.basePen for details\n\t\thow that works.\n\t\t\"\"\"\n\t\tglyfTable = self._glyphset._glyphs\n\t\tglyph = self._glyph\n\t\toffset = self.lsb - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n\t\tglyph.draw(pen, glyfTable, offset)\n\n\tdef drawPoints(self, pen):\n\t\t\"\"\"Draw the glyph onto PointPen. See fontTools.pens.pointPen\n\t\tfor details how that works.\n\t\t\"\"\"\n\t\tglyfTable = self._glyphset._glyphs\n\t\tglyph = self._glyph\n\t\toffset = self.lsb - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n\t\tglyph.drawPoints(pen, glyfTable, offset)\n\n\n\nclass _TTVarGlyphSet(_TTGlyphSet):\n\n\tdef __init__(self, font, location, normalized=False):\n\t\tself._ttFont = font\n\t\tself._glyphs = font['glyf']\n\n\t\tif not normalized:\n\t\t\tfrom fontTools.varLib.models import normalizeLocation, piecewiseLinearMap\n\n\t\t\taxes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in font['fvar'].axes}\n\t\t\tlocation = normalizeLocation(location, axes)\n\t\t\tif 'avar' in font:\n\t\t\t\tavar = font['avar']\n\t\t\t\tavarSegments = avar.segments\n\t\t\t\tnew_location = {}\n\t\t\t\tfor axis_tag, value in location.items():\n\t\t\t\t\tavarMapping = avarSegments.get(axis_tag, None)\n\t\t\t\t\tif avarMapping is not None:\n\t\t\t\t\t\tvalue = piecewiseLinearMap(value, avarMapping)\n\t\t\t\t\tnew_location[axis_tag] = value\n\t\t\t\tlocation = new_location\n\t\t\t\tdel new_location\n\n\t\tself.location = location\n\n\tdef __getitem__(self, glyphName):\n\t\tif glyphName not in self._glyphs:\n\t\t\traise KeyError(glyphName)\n\t\treturn _TTVarGlyphGlyf(self._ttFont, glyphName, self.location)\n\n\ndef _setCoordinates(glyph, coord, glyfTable):\n\t# Handle phantom points for (left, right, top, bottom) positions.\n\tassert len(coord) >= 4\n\tif not hasattr(glyph, 'xMin'):\n\t\tglyph.recalcBounds(glyfTable)\n\tleftSideX = coord[-4][0]\n\trightSideX = coord[-3][0]\n\ttopSideY = coord[-2][1]\n\tbottomSideY = coord[-1][1]\n\n\tfor _ in range(4):\n\t\tdel coord[-1]\n\n\tif glyph.isComposite():\n\t\tassert len(coord) == len(glyph.components)\n\t\tfor p,comp in zip(coord, glyph.components):\n\t\t\tif hasattr(comp, 'x'):\n\t\t\t\tcomp.x,comp.y = p\n\telif glyph.numberOfContours == 0:\n\t\tassert len(coord) == 0\n\telse:\n\t\tassert len(coord) == len(glyph.coordinates)\n\t\tglyph.coordinates = coord\n\n\tglyph.recalcBounds(glyfTable)\n\n\thorizontalAdvanceWidth = otRound(rightSideX - leftSideX)\n\tverticalAdvanceWidth = otRound(topSideY - bottomSideY)\n\tleftSideBearing = otRound(glyph.xMin - leftSideX)\n\ttopSideBearing = otRound(topSideY - glyph.yMax)\n\treturn (\n\t\thorizontalAdvanceWidth,\n\t\tleftSideBearing,\n\t\tverticalAdvanceWidth,\n\t\ttopSideBearing,\n\t)\n\n\nclass _TTVarGlyph(_TTGlyph):\n\tdef __init__(self, ttFont, glyphName, location):\n\t\tself._ttFont = ttFont\n\t\tself._glyphName = glyphName\n\t\tself._location = location\n\t\t# draw() fills these in\n\t\tself.width = self.height = self.lsb = self.tsb = None\n\n\nclass _TTVarGlyphGlyf(_TTVarGlyph):\n\n\tdef draw(self, pen):\n\t\tfrom fontTools.varLib.iup import iup_delta\n\t\tfrom fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates\n\t\tfrom fontTools.varLib.models import supportScalar\n\n\t\tglyf = self._ttFont['glyf']\n\t\thMetrics = self._ttFont['hmtx'].metrics\n\t\tvMetrics = getattr(self._ttFont.get('vmtx'), 'metrics', None)\n\n\t\tvariations = self._ttFont['gvar'].variations[self._glyphName]\n\t\tcoordinates, _ = glyf._getCoordinatesAndControls(self._glyphName, hMetrics, vMetrics)\n\t\torigCoords, endPts = None, None\n\t\tfor var in variations:\n\t\t\tscalar = supportScalar(self._location, var.axes)\n\t\t\tif not scalar:\n\t\t\t\tcontinue\n\t\t\tdelta = var.coordinates\n\t\t\tif None in delta:\n\t\t\t\tif origCoords is None:\n\t\t\t\t\torigCoords,control = glyf._getCoordinatesAndControls(self._glyphName, hMetrics, vMetrics)\n\t\t\t\t\tendPts = control[1] if control[0] >= 1 else list(range(len(control[1])))\n\t\t\t\tdelta = iup_delta(delta, origCoords, endPts)\n\t\t\tcoordinates += GlyphCoordinates(delta) * scalar\n\n\t\tglyph = copy(glyf[self._glyphName]) # Shallow copy\n\t\twidth, lsb, height, tsb = _setCoordinates(glyph, coordinates, glyf)\n\t\tself.width = width\n\t\tself.lsb = lsb\n\t\tself.height = height\n\t\tself.tsb = tsb\n\t\toffset = lsb - glyph.xMin if hasattr(glyph, \"xMin\") else 0\n\t\tglyph.draw(pen, glyf, offset)\n", "path": "Lib/fontTools/ttLib/ttGlyphSet.py"}]}