Giter Club home page Giter Club logo

Comments (7)

readroberts avatar readroberts commented on July 3, 2024 1

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.

brawer avatar brawer commented on July 3, 2024

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.

brawer avatar brawer commented on July 3, 2024

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.

readroberts avatar readroberts commented on July 3, 2024

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.

readroberts avatar readroberts commented on July 3, 2024

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.

schriftgestalt avatar schriftgestalt commented on July 3, 2024

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.

schriftgestalt avatar schriftgestalt commented on July 3, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.