Merge pull request #2161 from fonttools/fix-woff2-offcurve-overlap-flag
WOFF2: An off-curve should stay off even with flags
This commit is contained in:
commit
c4027c0e67
@ -11,7 +11,7 @@ from fontTools.ttLib import (TTFont, TTLibError, getTableModule, getTableClass,
|
||||
from fontTools.ttLib.sfnt import (SFNTReader, SFNTWriter, DirectoryEntry,
|
||||
WOFFFlavorData, sfntDirectoryFormat, sfntDirectorySize, SFNTDirectoryEntry,
|
||||
sfntDirectoryEntrySize, calcChecksum)
|
||||
from fontTools.ttLib.tables import ttProgram
|
||||
from fontTools.ttLib.tables import ttProgram, _g_l_y_f
|
||||
import logging
|
||||
|
||||
|
||||
@ -934,7 +934,7 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
flags = array.array('B')
|
||||
triplets = array.array('B')
|
||||
for i in range(len(coordinates)):
|
||||
onCurve = glyph.flags[i]
|
||||
onCurve = glyph.flags[i] & _g_l_y_f.flagOnCurve
|
||||
x, y = coordinates[i]
|
||||
absX = abs(x)
|
||||
absY = abs(y)
|
||||
|
3
NEWS.rst
3
NEWS.rst
@ -1,3 +1,6 @@
|
||||
- [woff2] An initial off-curve point with an overlap flag now stays an off-curve
|
||||
point after compression.
|
||||
|
||||
4.19.0 (released 2021-01-25)
|
||||
----------------------------
|
||||
|
||||
|
306
Tests/ttLib/data/woff2_overlap_offcurve_in.ttx
Normal file
306
Tests/ttLib/data/woff2_overlap_offcurve_in.ttx
Normal file
@ -0,0 +1,306 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.18">
|
||||
|
||||
<GlyphOrder>
|
||||
<!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="A"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<head>
|
||||
<!-- Most of this table will be recalculated by the compiler -->
|
||||
<tableVersion value="1.0"/>
|
||||
<fontRevision value="1.0"/>
|
||||
<checkSumAdjustment value="0x9aec19bb"/>
|
||||
<magicNumber value="0x5f0f3cf5"/>
|
||||
<flags value="00000000 00000010"/>
|
||||
<unitsPerEm value="1000"/>
|
||||
<created value="Thu Jan 28 15:17:57 2021"/>
|
||||
<modified value="Thu Jan 28 15:52:10 2021"/>
|
||||
<xMin value="178"/>
|
||||
<yMin value="72"/>
|
||||
<xMax value="586"/>
|
||||
<yMax value="480"/>
|
||||
<macStyle value="00000000 00000000"/>
|
||||
<lowestRecPPEM value="6"/>
|
||||
<fontDirectionHint value="2"/>
|
||||
<indexToLocFormat value="0"/>
|
||||
<glyphDataFormat value="0"/>
|
||||
</head>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="0x00010000"/>
|
||||
<ascent value="750"/>
|
||||
<descent value="-250"/>
|
||||
<lineGap value="100"/>
|
||||
<advanceWidthMax value="639"/>
|
||||
<minLeftSideBearing value="178"/>
|
||||
<minRightSideBearing value="53"/>
|
||||
<xMaxExtent value="586"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
<numberOfHMetrics value="2"/>
|
||||
</hhea>
|
||||
|
||||
<maxp>
|
||||
<!-- Most of this table will be recalculated by the compiler -->
|
||||
<tableVersion value="0x10000"/>
|
||||
<numGlyphs value="2"/>
|
||||
<maxPoints value="20"/>
|
||||
<maxContours value="1"/>
|
||||
<maxCompositePoints value="0"/>
|
||||
<maxCompositeContours value="0"/>
|
||||
<maxZones value="1"/>
|
||||
<maxTwilightPoints value="0"/>
|
||||
<maxStorage value="0"/>
|
||||
<maxFunctionDefs value="0"/>
|
||||
<maxInstructionDefs value="0"/>
|
||||
<maxStackElements value="0"/>
|
||||
<maxSizeOfInstructions value="0"/>
|
||||
<maxComponentElements value="0"/>
|
||||
<maxComponentDepth value="0"/>
|
||||
</maxp>
|
||||
|
||||
<OS_2>
|
||||
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
|
||||
will be recalculated by the compiler -->
|
||||
<version value="4"/>
|
||||
<xAvgCharWidth value="445"/>
|
||||
<usWeightClass value="400"/>
|
||||
<usWidthClass value="5"/>
|
||||
<fsType value="00000000 00000100"/>
|
||||
<ySubscriptXSize value="650"/>
|
||||
<ySubscriptYSize value="600"/>
|
||||
<ySubscriptXOffset value="0"/>
|
||||
<ySubscriptYOffset value="75"/>
|
||||
<ySuperscriptXSize value="650"/>
|
||||
<ySuperscriptYSize value="600"/>
|
||||
<ySuperscriptXOffset value="0"/>
|
||||
<ySuperscriptYOffset value="350"/>
|
||||
<yStrikeoutSize value="50"/>
|
||||
<yStrikeoutPosition value="300"/>
|
||||
<sFamilyClass value="0"/>
|
||||
<panose>
|
||||
<bFamilyType value="0"/>
|
||||
<bSerifStyle value="0"/>
|
||||
<bWeight value="0"/>
|
||||
<bProportion value="0"/>
|
||||
<bContrast value="0"/>
|
||||
<bStrokeVariation value="0"/>
|
||||
<bArmStyle value="0"/>
|
||||
<bLetterForm value="0"/>
|
||||
<bMidline value="0"/>
|
||||
<bXHeight value="0"/>
|
||||
</panose>
|
||||
<ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
|
||||
<achVendID value="NONE"/>
|
||||
<fsSelection value="00000000 11000000"/>
|
||||
<usFirstCharIndex value="65"/>
|
||||
<usLastCharIndex value="65"/>
|
||||
<sTypoAscender value="750"/>
|
||||
<sTypoDescender value="-250"/>
|
||||
<sTypoLineGap value="100"/>
|
||||
<usWinAscent value="750"/>
|
||||
<usWinDescent value="250"/>
|
||||
<ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<sxHeight value="500"/>
|
||||
<sCapHeight value="700"/>
|
||||
<usDefaultChar value="0"/>
|
||||
<usBreakChar value="32"/>
|
||||
<usMaxContext value="0"/>
|
||||
</OS_2>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="250" lsb="0"/>
|
||||
<mtx name="A" width="639" lsb="178"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="0" platEncID="3" language="0">
|
||||
<map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
|
||||
</cmap_format_4>
|
||||
<cmap_format_4 platformID="3" platEncID="1" language="0">
|
||||
<map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
|
||||
</cmap_format_4>
|
||||
</cmap>
|
||||
|
||||
<loca>
|
||||
<!-- The 'loca' table will be calculated by the compiler -->
|
||||
</loca>
|
||||
|
||||
<glyf>
|
||||
|
||||
<!-- The xMin, yMin, xMax and yMax values
|
||||
will be recalculated by the compiler. -->
|
||||
|
||||
<TTGlyph name=".notdef"/><!-- contains no outline data -->
|
||||
|
||||
<TTGlyph name="A" xMin="178" yMin="72" xMax="586" yMax="480">
|
||||
<contour>
|
||||
<pt x="382" y="72" on="0" overlap="1"/>
|
||||
<pt x="336" y="72" on="1"/>
|
||||
<pt x="261" y="101" on="0"/>
|
||||
<pt x="207" y="155" on="0"/>
|
||||
<pt x="178" y="230" on="0"/>
|
||||
<pt x="178" y="276" on="1"/>
|
||||
<pt x="178" y="322" on="0"/>
|
||||
<pt x="207" y="397" on="0"/>
|
||||
<pt x="261" y="451" on="0"/>
|
||||
<pt x="336" y="480" on="0"/>
|
||||
<pt x="382" y="480" on="1"/>
|
||||
<pt x="428" y="480" on="0"/>
|
||||
<pt x="503" y="451" on="0"/>
|
||||
<pt x="557" y="397" on="0"/>
|
||||
<pt x="586" y="322" on="0"/>
|
||||
<pt x="586" y="276" on="1"/>
|
||||
<pt x="586" y="230" on="0"/>
|
||||
<pt x="557" y="155" on="0"/>
|
||||
<pt x="503" y="101" on="0"/>
|
||||
<pt x="428" y="72" on="0"/>
|
||||
</contour>
|
||||
<instructions/>
|
||||
</TTGlyph>
|
||||
|
||||
</glyf>
|
||||
|
||||
<name>
|
||||
<namerecord nameID="256" platformID="1" platEncID="0" langID="0x0" unicode="True">
|
||||
Weight
|
||||
</namerecord>
|
||||
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
|
||||
Unnamed
|
||||
</namerecord>
|
||||
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
|
||||
Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
|
||||
1.000;NONE;Unnamed-Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
|
||||
Unnamed Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
|
||||
Version 1.000
|
||||
</namerecord>
|
||||
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
|
||||
Unnamed-Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
|
||||
Weight
|
||||
</namerecord>
|
||||
</name>
|
||||
|
||||
<post>
|
||||
<formatType value="2.0"/>
|
||||
<italicAngle value="0.0"/>
|
||||
<underlinePosition value="-100"/>
|
||||
<underlineThickness value="50"/>
|
||||
<isFixedPitch value="0"/>
|
||||
<minMemType42 value="0"/>
|
||||
<maxMemType42 value="0"/>
|
||||
<minMemType1 value="0"/>
|
||||
<maxMemType1 value="0"/>
|
||||
<psNames>
|
||||
<!-- This file uses unique glyph names based on the information
|
||||
found in the 'post' table. Since these names might not be unique,
|
||||
we have to invent artificial names in case of clashes. In order to
|
||||
be able to retain the original information, we need a name to
|
||||
ps name mapping for those cases where they differ. That's what
|
||||
you see below.
|
||||
-->
|
||||
</psNames>
|
||||
<extraNames>
|
||||
<!-- following are the name that are not taken from the standard Mac glyph order -->
|
||||
</extraNames>
|
||||
</post>
|
||||
|
||||
<gasp>
|
||||
<gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="15"/>
|
||||
</gasp>
|
||||
|
||||
<HVAR>
|
||||
<Version value="0x00010000"/>
|
||||
<VarStore Format="1">
|
||||
<Format value="1"/>
|
||||
<VarRegionList>
|
||||
<!-- RegionAxisCount=1 -->
|
||||
<!-- RegionCount=1 -->
|
||||
<Region index="0">
|
||||
<VarRegionAxis index="0">
|
||||
<StartCoord value="0.0"/>
|
||||
<PeakCoord value="1.0"/>
|
||||
<EndCoord value="1.0"/>
|
||||
</VarRegionAxis>
|
||||
</Region>
|
||||
</VarRegionList>
|
||||
<!-- VarDataCount=1 -->
|
||||
<VarData index="0">
|
||||
<!-- ItemCount=2 -->
|
||||
<NumShorts value="0"/>
|
||||
<!-- VarRegionCount=0 -->
|
||||
<Item index="0" value="[]"/>
|
||||
<Item index="1" value="[]"/>
|
||||
</VarData>
|
||||
</VarStore>
|
||||
</HVAR>
|
||||
|
||||
<STAT>
|
||||
<Version value="0x00010001"/>
|
||||
<DesignAxisRecordSize value="8"/>
|
||||
<!-- DesignAxisCount=1 -->
|
||||
<DesignAxisRecord>
|
||||
<Axis index="0">
|
||||
<AxisTag value="wght"/>
|
||||
<AxisNameID value="256"/> <!-- Weight -->
|
||||
<AxisOrdering value="0"/>
|
||||
</Axis>
|
||||
</DesignAxisRecord>
|
||||
<!-- AxisValueCount=0 -->
|
||||
<ElidedFallbackNameID value="2"/> <!-- Regular -->
|
||||
</STAT>
|
||||
|
||||
<fvar>
|
||||
|
||||
<!-- Weight -->
|
||||
<Axis>
|
||||
<AxisTag>wght</AxisTag>
|
||||
<Flags>0x0</Flags>
|
||||
<MinValue>400.0</MinValue>
|
||||
<DefaultValue>400.0</DefaultValue>
|
||||
<MaxValue>700.0</MaxValue>
|
||||
<AxisNameID>256</AxisNameID>
|
||||
</Axis>
|
||||
</fvar>
|
||||
|
||||
<gvar>
|
||||
<version value="1"/>
|
||||
<reserved value="0"/>
|
||||
<glyphVariations glyph="A">
|
||||
<tuple>
|
||||
<coord axis="wght" value="1.0"/>
|
||||
<delta pt="0" x="-64" y="-44"/>
|
||||
<delta pt="5" x="-138" y="30"/>
|
||||
<delta pt="7" x="-127" y="73"/>
|
||||
<delta pt="8" x="-108" y="92"/>
|
||||
<delta pt="10" x="-64" y="103"/>
|
||||
<delta pt="12" x="-21" y="92"/>
|
||||
<delta pt="13" x="-2" y="73"/>
|
||||
<delta pt="16" x="9" y="13"/>
|
||||
<delta pt="17" x="-2" y="-14"/>
|
||||
<delta pt="18" x="-21" y="-33"/>
|
||||
</tuple>
|
||||
</glyphVariations>
|
||||
</gvar>
|
||||
|
||||
</ttFont>
|
@ -1,6 +1,7 @@
|
||||
from fontTools.misc.py23 import *
|
||||
from fontTools import ttLib
|
||||
from fontTools.ttLib import woff2
|
||||
from fontTools.ttLib.tables import _g_l_y_f
|
||||
from fontTools.ttLib.woff2 import (
|
||||
WOFF2Reader, woff2DirectorySize, woff2DirectoryFormat,
|
||||
woff2FlagsSize, woff2UnknownTagSize, woff2Base128MaxSize, WOFF2DirectoryEntry,
|
||||
@ -1220,6 +1221,20 @@ class WOFF2RoundtripTest(object):
|
||||
assert tmp.getvalue() == tmp2.getvalue()
|
||||
assert ttFont.flavor == "woff2"
|
||||
|
||||
def test_roundtrip_off_curve_despite_overlap_bit(self):
|
||||
ttx = os.path.join(data_dir, "woff2_overlap_offcurve_in.ttx")
|
||||
ttFont = ttLib.TTFont()
|
||||
ttFont.importXML(ttx)
|
||||
|
||||
assert ttFont["glyf"]["A"].flags[0] == _g_l_y_f.flagOverlapSimple
|
||||
|
||||
ttFont.flavor = "woff2"
|
||||
tmp = BytesIO()
|
||||
ttFont.save(tmp)
|
||||
|
||||
_, ttFont2 = self.roundtrip(tmp)
|
||||
assert ttFont2.flavor == "woff2"
|
||||
assert ttFont2["glyf"]["A"].flags[0] == 0
|
||||
|
||||
class MainTest(object):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user