Comments (7)
I just checked, and makeotfexe does still assign NULL anchors , but emits a warning:, e.g. """:[WARNING] MarkToBase or MarkToMark error in feature 'test'. Glyph 'caron' does not have an anchor point for a mark class that was used in a previous statement in the same lookup table. Setting the anchor point offset to 0.""" This behavior is what we decided was correct, after considerable discussion - see note above, from May 25, 2016. Georg is free to change the code to simply make this a fatal error - a very minor change, and perhaps preferable to change Glyphs to look for specific warnings emitted by makeotfexe. I think it it would be a bad idea to change back to the prior behavior setting an anchor point location of (0,0) rather than a NULL anchor.
from afdko.
Interestingly, this issue seems to trigger only for GPOS types 4 and 6. For type 5, makeotf is able to produce empty anchors perfectly fine. Here is a (very) made-up feature file where the output contains a type 5 MarkLigPos subtable with empty LigatureAnchors, just as expected:
markClass [acute grave] <anchor 500 700> @TOP_MARKS;
markClass macron <anchor 500 750> @TOP_MARKS;
markClass [cedilla] <anchor 500 -10> @BOTTOM_MARKS;
markClass [ogonek] <anchor 800 -10> @OGONEK;
feature test {
position
ligature [c_t s_t]
<anchor 500 800> mark @TOP_MARKS
<anchor 500 -200> mark @BOTTOM_MARKS
ligComponent
<anchor 1500 800> mark @TOP_MARKS
<anchor 1500 -200> mark @BOTTOM_MARKS
<anchor 1550 0> mark @OGONEK;
position
ligature fl
<anchor 300 800> mark @TOP_MARKS
<anchor 300 -200> mark @BOTTOM_MARKS
ligComponent
<anchor 600 800> mark @TOP_MARKS
<anchor 600 -200> mark @BOTTOM_MARKS;
position
ligature [f_f_l]
<anchor 300 800> mark @TOP_MARKS
<anchor 300 -200> mark @BOTTOM_MARKS
ligComponent
<anchor 600 800> mark @TOP_MARKS
<anchor 600 -200> mark @BOTTOM_MARKS
ligComponent
<anchor 900 800> mark @TOP_MARKS
<anchor 900 -200> mark @BOTTOM_MARKS;
} test;
Here’s the result from makeotf; note how <LigatureAnchor index="2" empty="1"/>
appears seven times in the output. So, GPOS type 5 is working as expected; the problem seems to be constrained to GPOS types 4 and 6.
<GPOS>
<Version value="1.0"/>
<ScriptList>
<!-- ScriptCount=1 -->
<ScriptRecord index="0">
<ScriptTag value="DFLT"/>
<Script>
<DefaultLangSys>
<ReqFeatureIndex value="65535"/>
<!-- FeatureCount=1 -->
<FeatureIndex index="0" value="0"/>
</DefaultLangSys>
<!-- LangSysCount=0 -->
</Script>
</ScriptRecord>
</ScriptList>
<FeatureList>
<!-- FeatureCount=1 -->
<FeatureRecord index="0">
<FeatureTag value="test"/>
<Feature>
<!-- LookupCount=1 -->
<LookupListIndex index="0" value="0"/>
</Feature>
</FeatureRecord>
</FeatureList>
<LookupList>
<!-- LookupCount=1 -->
<Lookup index="0">
<!-- LookupType=5 -->
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<MarkLigPos index="0" Format="1">
<MarkCoverage>
<Glyph value="grave"/>
<Glyph value="acute"/>
<Glyph value="macron"/>
<Glyph value="cedilla"/>
<Glyph value="ogonek"/>
</MarkCoverage>
<LigatureCoverage>
<Glyph value="fl"/>
<Glyph value="c_t"/>
<Glyph value="f_f_l"/>
<Glyph value="s_t"/>
</LigatureCoverage>
<!-- ClassCount=3 -->
<MarkArray>
<!-- MarkCount=5 -->
<MarkRecord index="0">
<Class value="0"/>
<MarkAnchor Format="1">
<XCoordinate value="500"/>
<YCoordinate value="700"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="1">
<Class value="0"/>
<MarkAnchor Format="1">
<XCoordinate value="500"/>
<YCoordinate value="700"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="2">
<Class value="0"/>
<MarkAnchor Format="1">
<XCoordinate value="500"/>
<YCoordinate value="750"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="3">
<Class value="1"/>
<MarkAnchor Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-10"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="4">
<Class value="2"/>
<MarkAnchor Format="1">
<XCoordinate value="800"/>
<YCoordinate value="-10"/>
</MarkAnchor>
</MarkRecord>
</MarkArray>
<LigatureArray>
<!-- LigatureCount=4 -->
<LigatureAttach index="0">
<!-- ComponentCount=2 -->
<ComponentRecord index="0">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="300"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="300"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
<ComponentRecord index="1">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="600"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="600"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
</LigatureAttach>
<LigatureAttach index="1">
<!-- ComponentCount=2 -->
<ComponentRecord index="0">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
<ComponentRecord index="1">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="1500"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="1500"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" Format="1">
<XCoordinate value="1550"/>
<YCoordinate value="0"/>
</LigatureAnchor>
</ComponentRecord>
</LigatureAttach>
<LigatureAttach index="2">
<!-- ComponentCount=3 -->
<ComponentRecord index="0">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="300"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="300"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
<ComponentRecord index="1">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="600"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="600"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
<ComponentRecord index="2">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="900"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="900"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
</LigatureAttach>
<LigatureAttach index="3">
<!-- ComponentCount=2 -->
<ComponentRecord index="0">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" empty="1"/>
</ComponentRecord>
<ComponentRecord index="1">
<LigatureAnchor index="0" Format="1">
<XCoordinate value="1500"/>
<YCoordinate value="800"/>
</LigatureAnchor>
<LigatureAnchor index="1" Format="1">
<XCoordinate value="1500"/>
<YCoordinate value="-200"/>
</LigatureAnchor>
<LigatureAnchor index="2" Format="1">
<XCoordinate value="1550"/>
<YCoordinate value="0"/>
</LigatureAnchor>
</ComponentRecord>
</LigatureAttach>
</LigatureArray>
</MarkLigPos>
</Lookup>
</LookupList>
</GPOS>
from afdko.
Here’s a feature file (again, entirely made up) that triggers the issue for GPOS type 6:
languagesystem DFLT dflt;
markClass [acute grave] <anchor 1 1 contourpoint 11> @TOP_MARKS;
markClass macron <anchor 2 2 contourpoint 22> @TOP_MARKS;
markClass [cedilla] <anchor 3 3 contourpoint 33> @BOTTOM_MARKS;
feature test {
position mark [acute grave macron ogonek]
<anchor 500 200> mark @TOP_MARKS
<anchor 500 -80> mark @BOTTOM_MARKS;
position mark [dieresis caron]
<anchor 500 200> mark @TOP_MARKS;
} test;
Observed output:
<GPOS>
<Version value="1.0"/>
<ScriptList>
<!-- ScriptCount=1 -->
<ScriptRecord index="0">
<ScriptTag value="DFLT"/>
<Script>
<DefaultLangSys>
<ReqFeatureIndex value="65535"/>
<!-- FeatureCount=1 -->
<FeatureIndex index="0" value="0"/>
</DefaultLangSys>
<!-- LangSysCount=0 -->
</Script>
</ScriptRecord>
</ScriptList>
<FeatureList>
<!-- FeatureCount=1 -->
<FeatureRecord index="0">
<FeatureTag value="test"/>
<Feature>
<!-- LookupCount=1 -->
<LookupListIndex index="0" value="0"/>
</Feature>
</FeatureRecord>
</FeatureList>
<LookupList>
<!-- LookupCount=1 -->
<Lookup index="0">
<!-- LookupType=6 -->
<LookupFlag value="0"/>
<!-- SubTableCount=1 -->
<MarkMarkPos index="0" Format="1">
<Mark1Coverage>
<Glyph value="grave"/>
<Glyph value="acute"/>
<Glyph value="macron"/>
<Glyph value="cedilla"/>
</Mark1Coverage>
<Mark2Coverage>
<Glyph value="grave"/>
<Glyph value="acute"/>
<Glyph value="dieresis"/>
<Glyph value="macron"/>
<Glyph value="ogonek"/>
<Glyph value="caron"/>
</Mark2Coverage>
<!-- ClassCount=2 -->
<Mark1Array>
<!-- MarkCount=4 -->
<MarkRecord index="0">
<Class value="0"/>
<MarkAnchor Format="2">
<XCoordinate value="1"/>
<YCoordinate value="1"/>
<AnchorPoint value="11"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="1">
<Class value="0"/>
<MarkAnchor Format="2">
<XCoordinate value="1"/>
<YCoordinate value="1"/>
<AnchorPoint value="11"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="2">
<Class value="0"/>
<MarkAnchor Format="2">
<XCoordinate value="2"/>
<YCoordinate value="2"/>
<AnchorPoint value="22"/>
</MarkAnchor>
</MarkRecord>
<MarkRecord index="3">
<Class value="1"/>
<MarkAnchor Format="2">
<XCoordinate value="3"/>
<YCoordinate value="3"/>
<AnchorPoint value="33"/>
</MarkAnchor>
</MarkRecord>
</Mark1Array>
<Mark2Array>
<!-- Mark2Count=6 -->
<Mark2Record index="0">
<Mark2Anchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="200"/>
</Mark2Anchor>
<Mark2Anchor index="1" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-80"/>
</Mark2Anchor>
</Mark2Record>
<Mark2Record index="1">
<Mark2Anchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="200"/>
</Mark2Anchor>
<Mark2Anchor index="1" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-80"/>
</Mark2Anchor>
</Mark2Record>
<Mark2Record index="2">
<Mark2Anchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="200"/>
</Mark2Anchor>
<Mark2Anchor index="1" Format="1">
<XCoordinate value="0"/>
<YCoordinate value="0"/>
</Mark2Anchor>
</Mark2Record>
<Mark2Record index="3">
<Mark2Anchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="200"/>
</Mark2Anchor>
<Mark2Anchor index="1" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-80"/>
</Mark2Anchor>
</Mark2Record>
<Mark2Record index="4">
<Mark2Anchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="200"/>
</Mark2Anchor>
<Mark2Anchor index="1" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="-80"/>
</Mark2Anchor>
</Mark2Record>
<Mark2Record index="5">
<Mark2Anchor index="0" Format="1">
<XCoordinate value="500"/>
<YCoordinate value="200"/>
</Mark2Anchor>
<Mark2Anchor index="1" Format="1">
<XCoordinate value="0"/>
<YCoordinate value="0"/>
</Mark2Anchor>
</Mark2Record>
</Mark2Array>
</MarkMarkPos>
</Lookup>
</LookupList>
</GPOS>
Expected: Instead of specifying 0 as value for XCoordinate
and YCoordinate
, the sixth and the last Mark2Anchor should be <Mark2Anchor index="1" empty="1"/>
from afdko.
Yes, this is a bug that should be fixed in makeotf. I haven't noticed the issue because the Adobe type developers usually don't mix different mark classes in a single lookup, but it is certainly reasonable to do so.
from afdko.
After some discussion on the external opentype list, agreed that missing base-anchor to mark class pairs should not be allowed for GPOS formats 4 and 6. Changed makeotf to report an error for this case. See thread on external opentype list, [email protected], title " [OpenType] NULL offsets to anchor tables in GPOS lookups", April 28 2016.
from afdko.
Apple text layout seems to have problems with NULL offsets as written with the latest makeOTF: https://forum.glyphsapp.com/t/user-report-about-latest-makeotf/11487/5
from afdko.
My comment was mere feedback for the decision to use NULL anchors instead of add adding a 0/0 anchor as it was done before this discussion/change. So it seems that apples code is not handling that properly. I’ll tell them.
from afdko.
Related Issues (20)
- [otfstemhist] cannot specify glyphs via external glyph list
- [otfstemhist] -h reports unrelated options, wrong tool name HOT 1
- Unify format of external glyph names files across AFDKO tools
- [otfautohint/otfstemhist] Add tests
- use TTX tools to compile a otf file HOT 10
- [spot] alternate metrics ignored in class kern proof
- [otfautohint] (minor) outdated tool names
- [otfautohint] points “optimized away” in flex-like scenario (print only) HOT 15
- [tx] Crashing without error when using -decid option in -t1 mode
- Reordering of ligature substitution rules is considered harmful HOT 10
- [otfautohint] Mishinting of glyph? HOT 7
- [otfautohint] Consider adding flag to selectively skip overlap processing for some glyphs
- [makeotf] silently fails when GOADB has unexpected data
- [makeinstancesufo] & [checkoutlinesufo] multiprocessing vs progress bar, output improvement
- building fails on manjaro HOT 2
- [makeotf] substitution without target item does not fail HOT 8
- Pytest Error Encountered During AFDKO Compilation on Arch Linux HOT 6
- [checkoutlinesufo] XMLSyntaxError reading fontinfo.plist of temp UFO font HOT 3
- [makeotf] -r reports all unhinted glyphs individually HOT 1
- [buildmasterotfs] incompatible sources produced HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from afdko.