Added a kerning validator. This must be run by the caller since groups are required. This should resolve ticket #8.

git-svn-id: http://svn.robofab.com/branches/ufo3k@507 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
This commit is contained in:
Tal Leming 2011-12-06 18:46:31 +00:00
parent b836b3287a
commit ff01e27763
2 changed files with 98 additions and 1 deletions

View File

@ -352,6 +352,13 @@ class UFOReader(object):
def readKerning(self):
"""
Read kerning.plist. Returns a dict.
This performs structural validation of the kerning data,
but it does not check the validity of the kerning as
dictated in the UFO spec. To do that, pass the kerning
obtained from this method and the groups obtained from
readGroups to the kerningvalidator function in the
validators module.
"""
# handle up conversion
if self._formatVersion < 3:
@ -834,6 +841,11 @@ class UFOWriter(object):
"""
Write kerning.plist. This method requires a
dict of kerning pairs as an argument.
This performs basic structural validation of the kerning,
but it does not check for compliance with the spec in
regards to conflicting pairs. The assumption is that the
kerning data being passed is standards compliant.
"""
invalidFormatMessage = "The kerning is not properly formatted."
if not isDictEnough(kerning):

View File

@ -3,7 +3,6 @@
import os
import calendar
# -------
# Generic
# -------
@ -887,6 +886,92 @@ def groupsValidator(value):
d[glyphName] = groupName
return True, None
# -------------
# kerning.plist
# -------------
def kerningValidator(kerning, groups):
"""
This validates a passed kerning dictionary
using the provided groups. The validation
checks to make sure that there are no conflicting
glyph + group and group + glyph exceptions.
>>> groups = {
... "public.kern1.O" : ["O", "D", "Q"],
... "public.kern2.E" : ["E", "F"]
... }
>>> kerning = {
... ("public.kern1.O", "public.kern2.E") : -100,
... ("public.kern1.O", "F") : -200,
... ("D", "F") : -300,
... }
>>> kerningValidator(kerning, groups)
True
>>> kerning = {
... ("public.kern1.O", "public.kern2.E") : -100,
... ("public.kern1.O", "F") : -200,
... ("Q", "public.kern2.E") : -250,
... ("D", "F") : -300,
... }
>>> kerningValidator(kerning, groups)
False
"""
# flatten the groups
flatFirstGroups = {}
flatSecondGroups = {}
for groupName, glyphList in groups.items():
if not groupName.startswith("public.kern1.") and not groupName.startswith("public.kern2."):
continue
if groupName.startswith("public.kern1."):
d = flatFirstGroups
elif groupName.startswith("public.kern2."):
d = flatSecondGroups
for glyphName in glyphList:
d[glyphName] = groupName
# search for conflicts
for first, second in kerning.keys():
firstIsGroup = first.startswith("public.kern1.")
secondIsGroup = second.startswith("public.kern2.")
# skip anything other than glyph + group and group + glyph
if firstIsGroup and secondIsGroup:
continue
if not firstIsGroup and not secondIsGroup:
continue
# if the first is a glyph and it isn't in a group, skip
if not firstIsGroup:
if first not in flatFirstGroups:
continue
# if the second is a glyph and it isn't in a group, skip
if not secondIsGroup:
if second not in flatSecondGroups:
continue
# skip unknown things
if firstIsGroup and first not in groups:
continue
if firstIsGroup and second not in flatSecondGroups:
continue
if secondIsGroup and second not in groups:
continue
if secondIsGroup and first not in flatFirstGroups:
continue
# validate group + glyph
if firstIsGroup:
firstOptions = groups[first]
secondGroup = flatSecondGroups[second]
for glyph in firstOptions:
if (glyph, secondGroup) in kerning:
return False
# validate glyph + group
if secondIsGroup:
secondOptions = groups[second]
firstGroup = flatFirstGroups[first]
for glyph in secondOptions:
if (firstGroup, glyph) in kerning:
return False
# fallback
return True
# -------------
# lib.plist/lib
# -------------