@startuml v5_class_diagram

title
  Designspace v5 Class Diagram

  <size:12>Note: the ""Descriptor"" suffix is omitted from most classes
end title

' left to right direction

skinparam class {
BackgroundColor<<New>> PaleGreen
}

class DesignSpaceDocument {
+ formatVersion: str = None
+ <color:green><b><<New>> elidedFallbackName: str = None
+ rulesProcessingLast: bool = False
+ lib: Dict = {}
}

note left of DesignSpaceDocument::elidedFallbackName
STAT Style Attributes Header field ""elidedFallbackNameID""
end note

abstract class AbstractAxis {
+ tag: str
+ name: str
+ labelNames: Dict[str, str]
+ hidden: bool
+ map: List[Tuple[float, float]]
+ <color:green><b><<New>> axisOrdering: int
}
DesignSpaceDocument *-- "*" AbstractAxis: axes >
note right of AbstractAxis::axisOrdering
STAT Axis Record field
end note

class Axis {
+ minimum: float
+ maximum: float
+ default: float
}
AbstractAxis <|--- Axis
note bottom of Axis
This is the usual
Axis, with a range
of values.
end note

class DiscreteAxis <<New>> {
+ values: List[float]
+ default: float
}
AbstractAxis <|--- DiscreteAxis
note bottom of DiscreteAxis
A discrete axis is not
interpolable, e.g.
Uprights vs Italics, and
so has "discrete" stops
instead of a continuous
range of values.
end note

Axis .[hidden] DiscreteAxis

class AxisLabel <<New>> {
+ userMinimum: Optional[float]
+ userValue: float
+ userMaximum: Optional[float]
+ name: str
+ elidable: bool
+ olderSibling: bool
+ linkedUserValue: Optional[float]
+ labelNames: Dict[str, str]

+ getFormat(): 1 | 2 | 3
}
note right of AxisLabel
Label for a
stop on an Axis
(STAT format
1,2,3)
end note
AbstractAxis *-- "*" AxisLabel: <<New>> \n axisLabels >

class LocationLabel <<New>> {
+ name: str
+ location: Dict[str, float]
+ elidable: bool
+ olderSibling: bool
+ labelNames: Dict[str, str]
}
note right of LocationLabel
Label for a
freestanding
location
(STAT format 4)
end note
DesignSpaceDocument *--- "*" LocationLabel: <<New>> \n locationLabels >

class Rule {
+ name: str
+ conditionSets: List[ConditionSet]
+ subs: Dict[str, str]
}
DesignSpaceDocument *- "*" Rule: rules >

class Source {
+ name: Optional[str]
+ filename: str
+ path: str
+ layerName: Optional[str]
+ <color:brown><s><<Deprecated>> location: Location
+ <color:green><b><<New>> designLocation: AnisotropicLocation
....
+ font: Optional[Font]
....
+ familyName: Optional[str]
+ styleName: Optional[str]
+ <color:green><b><<New>> localisedFamilyName: Dict
....
+ <color:brown><s><<Deprecated>> copyLib: bool
+ <color:brown><s><<Deprecated>> copyInfo: bool
+ <color:brown><s><<Deprecated>> copyGroups: bool
+ <color:brown><s><<Deprecated>> copyFeatures: bool
....
+ muteKerning: bool
+ muteInfo: bool
+ mutedGlyphNames: List[str]
----
+ <color:green><b><<New>> getFullDesignLocation(doc)
}
DesignSpaceDocument *-- "*" Source: sources >
note right of Source::localisedFamilyName
New field to allow generation
of localised instance names using
STAT information.
end note
note right of Source::copyGroups
These fields are already not meaningful
anymore in version 4 (the default source
will be used as "neutral" for groups, info
and features. ''copyLib'' can be emulated
by putting content in the designspace's lib.
end note

note as NLocSource
The location of
sources can still only
be defined in design
coordinates, and now
also by relying on
axis defaults.

To build the final,
"full" location, a
helper method is
provided, that uses
axis defaults and
axis mappings to
fill in the blanks.
end note
NLocSource . Source::designLocation
NLocSource . Source::getFullDesignLocation

class VariableFont <<New>> {
+ filename: str
+ lib: Dict
}
DesignSpaceDocument *--- "*" VariableFont: <<New>> \n variableFonts >
note right of VariableFont
A variable font is a
subset of the designspace
where everything interpolates
(and so can be compiled into
an OpenType variable font).
end note

abstract class AbstractAxisSubset <<New>> {
+ name: str
}
VariableFont *-- "*" AbstractAxisSubset: <<New>> \n axisSubsets >

note right of AbstractAxisSubset
An axis subset selects a range
or a spot on each the available
axes from the whole designspace.

By default, only the default value
of each axis is used to define the
variable font.

Continuous axes can be specified
to include their full range instead;
or a subset of the range.

Discrete axes can be specified
to include a different spot than the
default.
end note

class RangeAxisSubset <<New>> {
+ userMinimum: float
+ userDefault: float
+ userMaximum: float
}
AbstractAxisSubset <|-- RangeAxisSubset

class ValueAxisSubset <<New>> {
+ userValue: float
}
AbstractAxisSubset <|-- ValueAxisSubset

class Instance {
+ filename: str
+ path: str
+ <color:brown><s><<Deprecated>> location: Location
+ <color:green><b><<New>> locationLabel: str
+ <color:green><b><<New>> designLocation: AnisotropicLocation
+ <color:green><b><<New>> userLocation: SimpleLocation
....
+ font: Optional[Font]
....
+ <color:orange><b><<Changed>> name: Optional[str]
+ <color:orange><b><<Changed>> familyName: Optional[str]
+ <color:orange><b><<Changed>> styleName: Optional[str]
+ <color:orange><b><<Changed>> postScriptFontName: Optional[str]
+ <color:orange><b><<Changed>> styleMapFamilyName: Optional[str]
+ <color:orange><b><<Changed>> styleMapStyleName: Optional[str]
+ localisedFamilyName: Dict
+ localisedStyleName: Dict
+ localisedStyleMapFamilyName: Dict
+ localisedStyleMapStyleName: Dict
....
+ <color:brown><s><<Deprecated>> glyphs: Dict
+ <color:brown><s><<Deprecated>> kerning: bool
+ <color:brown><s><<Deprecated>> info: bool
....
+ lib: Dict
----
+ <color:green><b><<New>> clearLocation()
+ <color:green><b><<New>> getLocationLabelDescriptor(doc)
+ <color:green><b><<New>> getFullDesignLocation(doc)
+ <color:green><b><<New>> getFullUserLocation(doc)
}
DesignSpaceDocument *-- "*" Instance: instances >
note right of Instance::locationLabel
The location can now alternatively
be a string = name of a LocationLabel
(STAT format 4). The instance then
adopts the location of that label.
See the Decovar example file.
end note
note right of Instance::styleMapStyleName
All the name field are now optional.
Their default values will be computed
using the provided STAT table data
and the STAT rules from the spec.
For styleMap{Family,Style}Name, they
would be computed using the STAT
""linkedUserValue"" fields.
end note
note right of Instance::glyphs
This attribute has been replaced by rules
end note
note right of Instance::kerning
All instances get kerning and info
nowadays.
end note

note as NLocInstance
The location of instances
can now be defined using
either:
- a STAT LocationLabel
- design coordinates
- user coordinates.
- relying on axis defaults

To build the final, "full"
location, a few helper
methods are provided,
that aggregate data from
these sources and apply
the axis mappings.
end note
NLocInstance . Instance::designLocation
NLocInstance . Instance::getFullDesignLocation

@enduml

