Skip to content

Commit

Permalink
Merge pull request #1018 from googlefonts/more-types
Browse files Browse the repository at this point in the history
More types
  • Loading branch information
justvanrossum authored Dec 11, 2023
2 parents e4cc253 + 52fb29d commit b908834
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 72 deletions.
80 changes: 80 additions & 0 deletions src/fontra/client/core/classes.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
"axes": {
"type": "list",
"subtype": "GlobalAxis"
},
"sources": {
"type": "list",
"subtype": "GlobalSource"
}
},
"VariableGlyph": {
Expand Down Expand Up @@ -66,6 +70,10 @@
"type": "dict",
"subtype": "float"
},
"locationBase": {
"type": "str",
"optional": true
},
"inactive": {
"type": "bool"
},
Expand Down Expand Up @@ -102,6 +110,14 @@
"verticalOrigin": {
"type": "float",
"optional": true
},
"anchors": {
"type": "list",
"subtype": "Anchor"
},
"guidelines": {
"type": "list",
"subtype": "Guideline"
}
},
"PackedPath": {
Expand Down Expand Up @@ -167,6 +183,40 @@
"type": "float"
}
},
"Anchor": {
"name": {
"type": "str"
},
"x": {
"type": "float"
},
"y": {
"type": "float"
},
"customData": {
"type": "dict",
"subtype": "Any"
}
},
"Guideline": {
"name": {
"type": "str",
"optional": true
},
"x": {
"type": "float"
},
"y": {
"type": "float"
},
"angle": {
"type": "float"
},
"customData": {
"type": "dict",
"subtype": "Any"
}
},
"GlobalAxis": {
"name": {
"type": "str"
Expand All @@ -193,5 +243,35 @@
"hidden": {
"type": "bool"
}
},
"GlobalSource": {
"name": {
"type": "str"
},
"location": {
"type": "dict",
"subtype": "float"
},
"verticalMetrics": {
"type": "dict",
"subtype": "GlobalMetric"
},
"guidelines": {
"type": "list",
"subtype": "Guideline"
},
"customData": {
"type": "dict",
"subtype": "Any"
}
},
"GlobalMetric": {
"value": {
"type": "float"
},
"customData": {
"type": "dict",
"subtype": "Any"
}
}
}
193 changes: 122 additions & 71 deletions src/fontra/core/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,87 @@

from .path import PackedPath, Path, Point, PointType

Location = dict[str, float]
CustomData = dict[str, Any]

@dataclass(kw_only=True)
class Font:
unitsPerEm: int = 1000
glyphs: dict[str, VariableGlyph] = field(default_factory=dict)
glyphMap: dict[str, list[int]] = field(default_factory=dict)
customData: CustomData = field(default_factory=dict)
axes: list[Union[GlobalAxis, GlobalDiscreteAxis]] = field(default_factory=list)
sources: list[GlobalSource] = field(default_factory=list)

def _trackAssignedAttributeNames(self):
# see fonthandler.py
self._assignedAttributeNames = set()

def __setattr__(self, attrName, value):
if hasattr(self, "_assignedAttributeNames"):
self._assignedAttributeNames.add(attrName)
super().__setattr__(attrName, value)


@dataclass(kw_only=True)
class Component:
class GlobalSource:
name: str
transformation: DecomposedTransform = field(default_factory=DecomposedTransform)
location: Location = field(default_factory=Location)
location: Location = field(default_factory=dict)
verticalMetrics: dict[str, GlobalMetric] = field(default_factory=dict)
guidelines: list[Union[Guideline, HorizontalGuideline, VerticalGuideline]] = field(
default_factory=list
)
customData: CustomData = field(default_factory=dict)


@dataclass(kw_only=True)
class StaticGlyph:
path: Union[PackedPath, Path] = field(default_factory=PackedPath)
components: list[Component] = field(default_factory=list)
xAdvance: Optional[float] = None
yAdvance: Optional[float] = None
verticalOrigin: Optional[float] = None
class GlobalMetric:
value: float
customData: CustomData = field(default_factory=dict)

def convertToPackedPaths(self):
return replace(self, path=self.path.asPackedPath())

def convertToPaths(self):
return replace(self, path=self.path.asPath())
@dataclass(kw_only=True)
class Guideline:
name: Optional[str]
x: float
y: float
angle: float
customData: CustomData = field(default_factory=dict)


@dataclass(kw_only=True)
class Source:
name: str
layerName: str
location: Location = field(default_factory=Location)
inactive: bool = False
customData: CustomData = field(default_factory=CustomData)
class HorizontalGuideline:
name: Optional[str]
y: float
customData: CustomData = field(default_factory=dict)


@dataclass(kw_only=True)
class Layer:
glyph: StaticGlyph
customData: CustomData = field(default_factory=CustomData)
class VerticalGuideline:
name: str | None
x: float
customData: CustomData = field(default_factory=dict)


@dataclass(kw_only=True)
class GlobalAxis:
name: str # this identifies the axis
label: str # a user friendly label
tag: str # the opentype 4-char tag
minValue: float
defaultValue: float
maxValue: float
mapping: list[list[float]] = field(default_factory=list)
hidden: bool = False


@dataclass(kw_only=True)
class GlobalDiscreteAxis:
name: str # this identifies the axis
label: str # a user friendly label
tag: str # the opentype 4-char tag
values: list[float]
defaultValue: float
mapping: list[list[float]] = field(default_factory=list)
hidden: bool = False


@dataclass(kw_only=True)
Expand All @@ -65,7 +107,7 @@ class VariableGlyph:
axes: list[LocalAxis] = field(default_factory=list)
sources: list[Source] = field(default_factory=list)
layers: dict[str, Layer] = field(default_factory=dict)
customData: CustomData = field(default_factory=CustomData)
customData: CustomData = field(default_factory=dict)

def convertToPackedPaths(self):
return _convertToPathType(self, True)
Expand All @@ -74,11 +116,59 @@ def convertToPaths(self):
return _convertToPathType(self, False)


def _hasAnyPathType(varGlyph, pathType):
return any(
isinstance(layer.glyph.path, pathType) for layer in varGlyph.layers.values()
@dataclass(kw_only=True)
class Source:
name: str
layerName: str
location: Location = field(default_factory=dict)
locationBase: Optional[str] = None
inactive: bool = False
customData: CustomData = field(default_factory=dict)


@dataclass(kw_only=True)
class Layer:
glyph: StaticGlyph
customData: CustomData = field(default_factory=dict)


@dataclass(kw_only=True)
class StaticGlyph:
path: Union[PackedPath, Path] = field(default_factory=PackedPath)
components: list[Component] = field(default_factory=list)
xAdvance: Optional[float] = None
yAdvance: Optional[float] = None
verticalOrigin: Optional[float] = None
anchors: list[Anchor] = field(default_factory=list)
guidelines: list[Union[Guideline, HorizontalGuideline, VerticalGuideline]] = field(
default_factory=list
)

def convertToPackedPaths(self):
return replace(self, path=self.path.asPackedPath())

def convertToPaths(self):
return replace(self, path=self.path.asPath())


@dataclass(kw_only=True)
class Component:
name: str
transformation: DecomposedTransform = field(default_factory=DecomposedTransform)
location: Location = field(default_factory=dict)


@dataclass(kw_only=True)
class Anchor:
name: str
x: float
y: float
customData: CustomData = field(default_factory=dict)


Location = dict[str, float]
CustomData = dict[str, Any]


def _convertToPathType(varGlyph, packedPath):
if not _hasAnyPathType(varGlyph, Path if packedPath else PackedPath):
Expand All @@ -97,49 +187,10 @@ def _convertToPathType(varGlyph, packedPath):
)


@dataclass(kw_only=True)
class GlobalAxis:
name: str # this identifies the axis
label: str # a user friendly label
tag: str # the opentype 4-char tag
minValue: float
defaultValue: float
maxValue: float
mapping: list[list[float]] = field(default_factory=list)
hidden: bool = False


@dataclass(kw_only=True)
class GlobalDiscreteAxis:
name: str # this identifies the axis
label: str # a user friendly label
tag: str # the opentype 4-char tag
values: list[float]
defaultValue: float
mapping: list[list[float]] = field(default_factory=list)
hidden: bool = False


GlyphSet = dict[str, VariableGlyph]
GlyphMap = dict[str, list[int]]


@dataclass(kw_only=True)
class Font:
unitsPerEm: int = 1000
glyphs: GlyphSet = field(default_factory=GlyphSet)
glyphMap: GlyphMap = field(default_factory=GlyphMap)
customData: CustomData = field(default_factory=CustomData)
axes: list[Union[GlobalAxis, GlobalDiscreteAxis]] = field(default_factory=list)

def _trackAssignedAttributeNames(self):
# see fonthandler.py
self._assignedAttributeNames = set()

def __setattr__(self, attrName, value):
if hasattr(self, "_assignedAttributeNames"):
self._assignedAttributeNames.add(attrName)
super().__setattr__(attrName, value)
def _hasAnyPathType(varGlyph, pathType):
return any(
isinstance(layer.glyph.path, pathType) for layer in varGlyph.layers.values()
)


def makeSchema(*classes, schema=None):
Expand Down
3 changes: 2 additions & 1 deletion test-common/fonts/MutatorSans.fontra/font-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@
"mapping": [],
"hidden": false
}
]
],
"sources": []
}

0 comments on commit b908834

Please sign in to comment.