Merge pull request #1091 from readroberts/master

[CFF2] Fixes for writing PrivateDict BlueValues and Subrs to XML.
This commit is contained in:
Cosimo Lupo 2017-11-06 10:13:57 +00:00 committed by GitHub
commit d91faeaf1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 100 additions and 76 deletions

View File

@ -614,6 +614,11 @@ class GlobalSubrsIndex(Index):
self.fdSelect = fdSelect
if fdArray:
self.fdArray = fdArray
if isCFF2:
# CFF2Subr's can have numeric arguments on the stack after the last operator.
self.subrClass = psCharStrings.CFF2Subr
self.charStringClass = psCharStrings.CFF2Subr
def produceItem(self, index, data, file, offset):
if self.private is not None:
@ -1972,12 +1977,7 @@ class DictCompiler(object):
def arg_number(self, num):
if isinstance(num, list):
blendList = num
firstNum = blendList[0]
data = [firstNum]
for blendNum in blendList[1:]:
data.append(blendNum - firstNum)
data = [encodeNumber(val) for val in data]
data = [encodeNumber(val) for val in num]
data.append(encodeNumber(1))
data.append(bytechr(blendOp))
datum = bytesjoin(data)
@ -2011,15 +2011,33 @@ class DictCompiler(object):
data.append(encodeNumber(num))
return bytesjoin(data)
def arg_delta_blend(self, value):
# A delta list with blend lists has to be *all* blend lists.
# We have a list of master value lists, where the nth master value list
# contains the absolute values from each master for the nth entry in the
# current array.
# We first convert these to relative values from the previous entry.
""" A delta list with blend lists has to be *all* blend lists.
The value is a list is arranged as follows.
[
[V0, d0..dn]
[V1, d0..dn]
...
[Vm, d0..dn]
]
V is the absolute coordinate value from the default font, and d0-dn are
the delta values from the n regions. Each V is an absolute coordinate
from the default font.
We want to return a list:
[
[v0, v1..vm]
[d0..dn]
...
[d0..dn]
numBlends
blendOp
]
where each v is relative to the previous default font value.
"""
numMasters = len(value[0])
numValues = len(value)
numStack = (numValues * numMasters) + 1
numBlends = len(value)
numStack = (numBlends * numMasters) + 1
if numStack > self.maxBlendStack:
# Figure out the max number of value we can blend
# and divide this list up into chunks of that size.
@ -2035,28 +2053,26 @@ class DictCompiler(object):
out.extend(out1)
value = value[numVal:]
else:
firstList = [0] * numValues
deltaList = [None] * (numValues)
firstList = [0] * numBlends
deltaList = [None] * numBlends
i = 0
prevValList = numMasters * [0]
while i < numValues:
masterValList = value[i]
firstVal = firstList[i] = masterValList[0] - prevValList[0]
j = 1
deltaEntry = (numMasters - 1) * [0]
while j < numMasters:
masterValDelta = masterValList[j] - prevValList[j]
deltaEntry[j - 1] = masterValDelta - firstVal
j += 1
deltaList[i] = deltaEntry
prevVal = 0
while i < numBlends:
# For PrivateDict BlueValues, the default font
# values are absolute, not relative.
# Must convert these back to relative coordinates
# befor writing to CFF2.
defaultValue = value[i][0]
firstList[i] = defaultValue - prevVal
prevVal = defaultValue
deltaList[i] = value[i][1:]
i += 1
prevValList = masterValList
relValueList = firstList
for blendList in deltaList:
relValueList.extend(blendList)
out = [encodeNumber(val) for val in relValueList]
out.append(encodeNumber(numValues))
out.append(encodeNumber(numBlends))
out.append(bytechr(blendOp))
return out

View File

@ -943,7 +943,8 @@ class T2CharString(object):
operators, opcodes = buildOperatorDict(t2Operators)
decompilerClass = SimpleT2Decompiler
outlineExtractor = T2OutlineExtractor
isCFF2 = False
def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None):
if program is None:
program = []
@ -1102,6 +1103,14 @@ class T2CharString(object):
args = []
else:
args.append(token)
if args:
if self.isCFF2:
# CFF2Subr's can have numeric arguments on the stack after the last operator.
args = [str(arg) for arg in args]
line = ' '.join(args)
xmlWriter.write(line)
else:
assert 0, "T2Charstring or Subr has items on the stack after last operator."
def fromXML(self, name, attrs, content):
from fontTools.misc.textTools import binary2num, readHex
@ -1136,6 +1145,8 @@ class T2CharString(object):
program.append(token)
self.setProgram(program)
class CFF2Subr(T2CharString):
isCFF2 = True
class T1CharString(T2CharString):
@ -1173,7 +1184,6 @@ class T1CharString(T2CharString):
extractor.execute(self)
self.width = extractor.width
class DictDecompiler(object):
operandEncoding = cffDictOperandEncoding
@ -1246,36 +1256,34 @@ class DictDecompiler(object):
def arg_array(self, name):
return self.popall()
def arg_blendList(self, name):
# The last item on the stack is the number of return values, aka numValues.
# before that we have [numValues: args from first master]
# then numValues blend lists, where each blend list is numMasters -1
# Total number of values is numValues + (numValues * (numMasters -1)), == numValues * numMasters.
# reformat list to be numReturnValues tuples, each tuple with nMaster values
"""
There may be non-blend args at the top of the stack. We first calculate
where the blend args start in the stack. These are the last
numMasters*numBlends) +1 args.
The blend args starts with numMasters relative coordinate values, the BlueValues in the list from the default master font. This is followed by
numBlends list of values. Each of value in one of these lists is the
Variable Font delta for the matching region.
We re-arrange this to be a list of numMaster entries. Each entry starts with the corresponding default font relative value, and is followed by
the delta values. We then convert the default values, the first item in each entry, to an absolute value.
"""
vsindex = self.dict.get('vsindex', 0)
numMasters = self.parent.getNumRegions(vsindex) + 1 # only a PrivateDict has blended ops.
numReturnValues = self.pop()
stackIndex = -numMasters * numReturnValues
args = self.stack[stackIndex:]
del self.stack[stackIndex:]
numBlends = self.pop()
args = self.popall()
numArgs = len(args)
value = [None]*numReturnValues
# The spec says that there should be no non-blended Blue Values,.
assert(numArgs == numMasters * numBlends)
value = [None]*numBlends
numDeltas = numMasters-1
i = 0
prevVal = 0
prevValueList = [0]*numMasters
while i < numReturnValues:
while i < numBlends:
newVal = args[i] + prevVal
blendList = [newVal]*numMasters
prevVal = newVal
masterOffset = numBlends + (i* numDeltas)
blendList = [newVal] + args[masterOffset:masterOffset+numDeltas]
value[i] = blendList
j = 1
while j < numMasters:
masterOffset = numReturnValues + (i* numDeltas)
mi = masterOffset +(j-1)
delta = args[i] + args[mi]
blendList[j]= delta + prevValueList[j]
j += 1
prevValueList = blendList
i += 1
return value

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ttFont sfntVersion="OTTO" ttLibVersion="3.5">
<ttFont sfntVersion="OTTO" ttLibVersion="3.18">
<GlyphOrder>
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
@ -12,12 +12,12 @@
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.00099"/>
<checkSumAdjustment value="0x5f8802c6"/>
<checkSumAdjustment value="0x3e077bd3"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00000000 00000011"/>
<unitsPerEm value="1000"/>
<created value="Fri Jan 6 11:41:20 2017"/>
<modified value="Fri Jan 6 09:34:43 2017"/>
<modified value="Thu Jan 12 22:37:13 2017"/>
<xMin value="51"/>
<yMin value="-115"/>
<xMax value="560"/>
@ -68,24 +68,24 @@
<FontDict index="0">
<Private>
<BlueValues>
<blend value="-20 -15 -13 -20 -15 -13"/>
<blend value="0 0 0 0 0 0"/>
<blend value="487 474 470 487 474 470"/>
<blend value="503 487 483 503 487 483"/>
<blend value="515 527 534 515 527 534"/>
<blend value="531 540 547 531 540 547"/>
<blend value="536 550 556 536 550 556"/>
<blend value="552 563 569 552 563 569"/>
<blend value="624 647 654 624 647 654"/>
<blend value="640 660 667 640 660 667"/>
<blend value="652 670 677 652 670 677"/>
<blend value="672 685 690 672 685 690"/>
<blend value="711 730 738 711 730 738"/>
<blend value="731 750 758 731 750 758"/>
<blend value="-20 5 7 0 5 7"/>
<blend value="0 -5 -7 0 -5 -7"/>
<blend value="487 -13 -17 0 -13 -17"/>
<blend value="503 -3 -3 0 -3 -3"/>
<blend value="515 28 39 0 28 39"/>
<blend value="531 -3 -3 0 -3 -3"/>
<blend value="536 5 4 0 5 4"/>
<blend value="552 -3 -3 0 -3 -3"/>
<blend value="624 12 13 0 12 13"/>
<blend value="640 -3 -3 0 -3 -3"/>
<blend value="652 -2 -2 0 -2 -2"/>
<blend value="672 -5 -7 0 -5 -7"/>
<blend value="711 6 9 0 6 9"/>
<blend value="731 0 0 0 0 0"/>
</BlueValues>
<OtherBlues>
<blend value="-232 -250 -255 -232 -250 -255"/>
<blend value="-222 -240 -245 -222 -240 -245"/>
<blend value="-232 -18 -23 0 -18 -23"/>
<blend value="-222 0 0 0 0 0"/>
</OtherBlues>
<FamilyBlues value="-20 0 473 491 525 540 549 562 644 659 669 689 729 749"/>
<FamilyOtherBlues value="-249 -239"/>
@ -93,18 +93,18 @@
<BlueShift value="7"/>
<BlueFuzz value="0"/>
<StdHW>
<blend value="74 55 26 50 46 26"/>
<blend value="74 -19 -48 -24 -28 -48"/>
</StdHW>
<StdVW>
<blend value="190 80 28 190 80 28"/>
<blend value="190 -110 -162 0 -110 -162"/>
</StdVW>
<StemSnapH>
<blend value="60 40 20 38 32 20"/>
<blend value="74 55 26 50 46 26"/>
<blend value="60 -20 -40 -22 -28 -40"/>
<blend value="74 1 -8 -2 0 -8"/>
</StemSnapH>
<StemSnapV>
<blend value="190 80 28 190 80 28"/>
<blend value="200 90 32 200 90 32"/>
<blend value="190 -110 -162 0 -110 -162"/>
<blend value="200 0 -6 0 0 -6"/>
</StemSnapV>
</Private>
</FontDict>