Dear UFO spec community,
In April-September 2013, Adobe has proposed its UFO extension to store PostScript hints. The discussion can be found at:
https://groups.google.com/d/topic/ufo-spec/mRlcDYg6Shg/discussion
https://groups.google.com/d/topic/ufo-spec/7toFE5w9Y0g/discussion
The method is now implemented in AFDKO:
https://github.com/adobe-type-tools/afdko
The method stores hinting information inside of the GLIF lib under the <key>com.adobe.type.autohint</key> as in:
<lib>
<dict>
<key>com.adobe.type.autohint</key>
<data>
<hintSetList>
<hintset pointTag="ab02">
<hstem pos="-14" width="211" />
<hstem pos="455" width="180" />
<hstem pos="856" width="211" />
<vstem pos="74" width="336" />
<vstem pos="819" width="336" />
</hintset>
<hintset pointTag="hr02">
<hstem pos="21" width="-21" />
<hstem pos="455" width="180" />
<hstem pos="739" width="328" />
<vstem pos="74" width="336" />
<vstem pos="850" width="305" />
</hintset>
</hintSetList>
</data>
</dict>
</lib>
As you will notice, the <data> section contains custom XML which is outside the namespace defined by the Apple plist.
THIS IS A PROBLEM.
The GLIF spec
http://unifiedfontobject.org/versions/ufo3/glif.html says:
"lib: Custom data storage. This element is a place to store authoring tool specific, user specific or otherwise arbitrary data for the glyph. lib mus have one child element that is structure as a dictionary formatted as an XML Property List."
The
http://unifiedfontobject.org/versions/ufo3/conventions.html#propertylist document links to the XML Property List (plist) DTD:
http://www.apple.com/DTDs/PropertyList-1.0.dtd
That DTD clearly says:
<!ELEMENT data (#PCDATA)> <!-- Contents interpreted as Base-64 encoded -->
This means that in fact, the above <data> section of any entry in the GLIF lib should be written like this:
<lib>
<dict>
<key>com.adobe.type.autohint</key>
<data>
ICA8aGludFNldExpc3Q+CiAgICA8aGludHNldCBwb2ludFRhZz0iYWIwMi
I+CiAgICAgIDxoc3RlbSBwb3M9Ii0xNCIgd2lkdGg9IjIxMSIgLz4KICAg
ICAgPGhzdGVtIHBvcz0iNDU1IiB3aWR0aD0iMTgwIiAvPgogICAgICA8aH
N0ZW0gcG9zPSI4NTYiIHdpZHRoPSIyMTEiIC8+CiAgICAgIDx2c3RlbSBw
b3M9Ijc0IiB3aWR0aD0iMzM2IiAvPgogICAgICA8dnN0ZW0gcG9zPSI4MT
kiIHdpZHRoPSIzMzYiIC8+CiAgICA8L2hpbnRzZXQ+CiAgICA8aGludHNl
dCBwb2ludFRhZz0iaHIwMiI+CiAgICAgIDxoc3RlbSBwb3M9IjIxIiB3aW
R0aD0iLTIxIiAvPgogICAgICA8aHN0ZW0gcG9zPSI0NTUiIHdpZHRoPSIx
ODAiIC8+CiAgICAgIDxoc3RlbSBwb3M9IjczOSIgd2lkdGg9IjMyOCIgLz
4KICAgICAgPHZzdGVtIHBvcz0iNzQiIHdpZHRoPSIzMzYiIC8+CiAgICAg
IDx2c3RlbSBwb3M9Ijg1MCIgd2lkdGg9IjMwNSIgLz4KICAgIDwvaGludH
NldD4KICA8L2hpbnRTZXRMaXN0Pgo=
</data>
</dict>
</lib>
Otherwise, the lib section inside the GLIF is not a valid plist!
Fortunately, the GLIF file itself is not a plist, so there should be no strict requirement that the stuff inside the data element of the lib should adhere to plist conventions.
As Adobe showed, the requirement to base64-encode contents of the data element is just impractical.
However, implementations are at risk. It seems that RoboFont does not quite well deal with any custom XML inside the lib's data element, it requires that the contents of the lib data element must be base64-encoded. On the other hand, AFDKO writes GLIF files where the contents of the lib data element is NOT base64-encoded.
At FontLab, we're using a similar approach to Adobe: we're using the lib data to store our TTH (visual TrueType hinting) info. The human-readable version is like this:
<lib>
<dict>
<key>com.fontlab.ttprogram</key>
<data>
<ttProgram>
<ttc code="doubleh" point1="dh01" point2="dh02"/>
<ttc code="mdeltah" point="dh02" delta="-8" ppm1="24" ppm2="24"/>
<ttc code="mdeltah" point="dh02" delta="8" ppm1="9" ppm2="9"/>
<ttc code="mdeltah" point="dh02" delta="-8" ppm1="14" ppm2="14"/>
<ttc code="mdeltah" point="dh02" delta="-8" ppm1="12" ppm2="12"/>
<ttc code="singleh" point1="dh02" point2="sh01" stem="X: 95"/>
</ttProgram>
</data>
</dict>
</lib>
But according to the strict GLIF spec, we'd have to store it like this:
<lib>
<dict>
<key>com.fontlab.ttprogram</key>
<data>
ICA8dHRQcm9ncmFtPgogICAgPHR0YyBjb2RlPSJkb3VibGVoIiBwb2ludD
E9ImRoMDEiIHBvaW50Mj0iZGgwMiIvPgogICAgPHR0YyBjb2RlPSJtZGVs
dGFoIiBwb2ludD0iZGgwMiIgZGVsdGE9Ii04IiBwcG0xPSIyNCIgcHBtMj
0iMjQiLz4KICAgIDx0dGMgY29kZT0ibWRlbHRhaCIgcG9pbnQ9ImRoMDIi
IGRlbHRhPSI4IiBwcG0xPSI5IiBwcG0yPSI5Ii8+CiAgICA8dHRjIGNvZG
U9Im1kZWx0YWgiIHBvaW50PSJkaDAyIiBkZWx0YT0iLTgiIHBwbTE9IjE0
IiBwcG0yPSIxNCIvPgogICAgPHR0YyBjb2RlPSJtZGVsdGFoIiBwb2ludD
0iZGgwMiIgZGVsdGE9Ii04IiBwcG0xPSIxMiIgcHBtMj0iMTIiLz4KICAg
IDx0dGMgY29kZT0ic2luZ2xlaCIgcG9pbnQxPSJkaDAyIiBwb2ludDI9In
NoMDEiIHN0ZW09Ilg6IDk1Ii8+CiAgPC90dFByb2dyYW0+Cg==
</data>
</dict>
</lib>
Currently, our vfb2ufo converter has a "-64" commandline switch.
If the switch is supplied, the data for both PostScript hinting (using <key>com.adobe.type.autohint</key>) and TrueType hinting (using <key>com.fontlab.ttprogram</key>) is written as base64-encoded.
If the switch is not supplied, both kinds of info are written in human-readable form (i.e. custom XML inside the <data> element).
When reading GLIF lib data, we automatically detect both flavors.
So the problem is:
1. Some implementations (RoboFont) rely on the fact that anything inside a GLIF lib data element is base64-encoded.
2. Some implementations (AFDKO) write custom XML inside a GLIF lib data element that is NOT base64-encoded.
3. The notation introduced by Adobe has been discussed here a year ago, and it was accepted by the UFO spec authors. (I was not aware of the plist requirement at the time, or I would have raised it back then). So while the non-base64 contents of GLIF lib data is against the spec, it has been sort-of authorized by the UFO spec community, but implementations struggle (and will continue to struggle) with this.
4. The base64-encoded representation of the GLIF lib data is ugly, non-readable and kind of defeats lots of purposes of UFO. It's tedious to work with.
5. The current form of human-readable <data> contents as used by Adobe (and, at this time, FontLab) is NOT VERY GOOD because it makes it virtually impossible to produce any kind of schema for the GLIF XML that would be valid. The GLIF XML should ultimately have a schema with a clearly defined set of permissible elements.
At FontLab, we'd prefer if the requirement to base-64 encode the contents of the <data> element inside a GLIF lib was lifted. However, the current method that Adobe uses is not good either.
The proper way to do it using XML would be that each vendor would reserve a custom XML namespace prefix (which could be referred by a namespace declaration if needed).
So, a serious implementation would look like this:
<?xml version="1.0" encoding="UTF-8"?>
<glyph name="o" format="1" xmlns="
http://unifiedfontobject.org"
xmlns:adobe="
http://type.adobe.com"
xmlns:fontlab="
http://fontlab.com">
(...)
<lib>
<dict>
<key>com.adobe.type.autohint</key>
<data>
<adobe:hintSetList>
<adobe:hintset pointTag="ab02">
<adobe:hstem pos="-14" width="211" />
<adobe:hstem pos="455" width="180" />
<adobe:hstem pos="856" width="211" />
<adobe:vstem pos="74" width="336" />
<adobe:vstem pos="819" width="336" />
</adobe:hintset>
<adobe:hintset pointTag="hr02">
<adobe:hstem pos="21" width="-21" />
<adobe:hstem pos="455" width="180" />
<adobe:hstem pos="739" width="328" />
<adobe:vstem pos="74" width="336" />
<adobe:vstem pos="850" width="305" />
</adobe:hintset>
</adobe:hintSetList>
</data>
</dict>
<dict>
<key>com.fontlab.ttprogram</key>
<data>
<fontlab:ttProgram>
<fontlab:ttc code="doubleh" point1="dh01" point2="dh02"/>
<fontlab:ttc code="mdeltah" point="dh02" delta="-8" ppm1="24" ppm2="24"/>
<fontlab:ttc code="mdeltah" point="dh02" delta="8" ppm1="9" ppm2="9"/>
<fontlab:ttc code="mdeltah" point="dh02" delta="-8" ppm1="14" ppm2="14"/>
<fontlab:ttc code="mdeltah" point="dh02" delta="-8" ppm1="12" ppm2="12"/>
<fontlab:ttc code="singleh" point1="dh02" point2="sh01" stem="X: 95"/>
</fontlab:ttProgram>
</data>
</dict>
</lib>
Note that the URIs used in the xmlns attributes do NOT have to be valid URLs. It's more like a convention, and the convention should be to "unreverse" the reversed domain notation and cut it at some point, e.g. at the level of a vendor. See
http://en.wikipedia.org/wiki/XML_namespace or
http://docstore.mik.ua/orelly/xml/schema/ch10_06.htm
AFAIK, the example I show above would be a structurally valid XML.
It would still not make the <lib> section to adhere to Apple's plist DTD, but this should not be a requirement, since the GLIF XML as a whole is not an Apple plist either.
I would very much appreciate comments and pointers towards resolving this.
Best,
Adam