Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Svg font does not support <use> in Safari #266

Closed
yisibl opened this issue Apr 9, 2021 · 8 comments
Closed

Svg font does not support <use> in Safari #266

yisibl opened this issue Apr 9, 2021 · 8 comments

Comments

@yisibl
Copy link
Contributor

yisibl commented Apr 9, 2021

nanoemoji --color_format=picosvg

The svg file:

<svg width="200" height="200" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <circle fill="#F49924" cx="100" cy="100" r="100" />
    <ellipse fill="#7E4418" cx="59.545" cy="71.818" rx="15" ry="21.818" />
    <ellipse fill="#7E4418" cx="140.455" cy="71.818" rx="15" ry="21.818" />
</svg>

TTX file:

 <SVG>
    <svgDoc endGlyphID="2" startGlyphID="2">
      <![CDATA[<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><defs/><g id="glyph2" transform="matrix(6 0 0 6 0 -950)"><path d="M200,100 A100 100 0 1 1 0,100 A100 100 0 1 1 200,100 Z" fill="#F49924"/><path d="M74.545,71.818 A15 21.818 0 1 1 44.545,71.818 A15 21.818 0 1 1 74.545,71.818 Z" fill="#7E4418" id="glyph2::1"/><use href="#glyph2::1" x="80.91"/></g></svg>]]>
    </svgDoc>
  </SVG>

I think Safari does not support <use href="#glyph2::1" x="80.91"/>, so the ellipse on the right is missing.

image

Expect:

image

Keynote

image

@anthrotype
Copy link
Member

Interesting, thanks for reporting. If it works on FireFox then this is a Safari bug. You should probably file an issue with Apple.
I wonder if it has anything to do with the way the id string is formatted, e.g. the presence of :: characters. Could you see if you change the id to something that only contains letters or numbers it works then? This is just a guess of course

@yisibl
Copy link
Contributor Author

yisibl commented Apr 9, 2021

I changed :: characters in ttx and rebuilt it to ttf, but it still doesn't work.

Although this is a bug in Safari, can we add an option not to generate use?

@yisibl
Copy link
Contributor Author

yisibl commented Apr 9, 2021

This is the ttx file after modifying the use id.

  <?xml version="1.0" encoding="UTF-8"?>
  <ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.21">

    <GlyphOrder>
      <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
      <GlyphID id="0" name=".notdef"/>
      <GlyphID id="1" name="space"/>
      <GlyphID id="2" name="f"/>
    </GlyphOrder>

    <head>
      <!-- Most of this table will be recalculated by the compiler -->
      <tableVersion value="1.0"/>
      <fontRevision value="1.0"/>
      <checkSumAdjustment value="0xac2d1b06"/>
      <magicNumber value="0x5f0f3cf5"/>
      <flags value="00000000 00000011"/>
      <unitsPerEm value="1024"/>
      <created value="Fri Apr  9 13:36:55 2021"/>
      <modified value="Fri Apr  9 13:36:55 2021"/>
      <xMin value="0"/>
      <yMin value="0"/>
      <xMax value="0"/>
      <yMax value="0"/>
      <macStyle value="00000000 00000000"/>
      <lowestRecPPEM value="6"/>
      <fontDirectionHint value="2"/>
      <indexToLocFormat value="0"/>
      <glyphDataFormat value="0"/>
    </head>

    <hhea>
      <tableVersion value="0x00010000"/>
      <ascent value="950"/>
      <descent value="-250"/>
      <lineGap value="0"/>
      <advanceWidthMax value="1200"/>
      <minLeftSideBearing value="0"/>
      <minRightSideBearing value="0"/>
      <xMaxExtent value="0"/>
      <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="3"/>
    </hhea>

    <maxp>
      <!-- Most of this table will be recalculated by the compiler -->
      <tableVersion value="0x10000"/>
      <numGlyphs value="3"/>
      <maxPoints value="0"/>
      <maxContours value="0"/>
      <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="1112"/>
      <usWeightClass value="400"/>
      <usWidthClass value="5"/>
      <fsType value="00000000 00000100"/>
      <ySubscriptXSize value="666"/>
      <ySubscriptYSize value="614"/>
      <ySubscriptXOffset value="0"/>
      <ySubscriptYOffset value="77"/>
      <ySuperscriptXSize value="666"/>
      <ySuperscriptYSize value="614"/>
      <ySuperscriptXOffset value="0"/>
      <ySuperscriptYOffset value="358"/>
      <yStrikeoutSize value="51"/>
      <yStrikeoutPosition value="307"/>
      <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="32"/>
      <usLastCharIndex value="102"/>
      <sTypoAscender value="950"/>
      <sTypoDescender value="-250"/>
      <sTypoLineGap value="0"/>
      <usWinAscent value="950"/>
      <usWinDescent value="250"/>
      <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
      <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
      <sxHeight value="512"/>
      <sCapHeight value="717"/>
      <usDefaultChar value="0"/>
      <usBreakChar value="32"/>
      <usMaxContext value="0"/>
    </OS_2>

    <hmtx>
      <mtx name=".notdef" width="0" lsb="0"/>
      <mtx name="f" width="1200" lsb="0"/>
      <mtx name="space" width="1024" lsb="0"/>
    </hmtx>

    <cmap>
      <tableVersion version="0"/>
      <cmap_format_4 platformID="0" platEncID="3" language="0">
        <map code="0x20" name="space"/><!-- SPACE -->
        <map code="0x66" name="f"/><!-- LATIN SMALL LETTER F -->
      </cmap_format_4>
      <cmap_format_4 platformID="3" platEncID="1" language="0">
        <map code="0x20" name="space"/><!-- SPACE -->
        <map code="0x66" name="f"/><!-- LATIN SMALL LETTER F -->
      </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="f"/><!-- contains no outline data -->

      <TTGlyph name="space"/><!-- contains no outline data -->

    </glyf>

    <name>
      <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
        iconfont
      </namerecord>
      <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
        Regular
      </namerecord>
      <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
        1.000;NONE;iconfont-Regular
      </namerecord>
      <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
        iconfont Regular
      </namerecord>
      <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
        Version 1.000
      </namerecord>
      <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
        iconfont-Regular
      </namerecord>
    </name>

    <post>
      <formatType value="3.0"/>
      <italicAngle value="0.0"/>
      <underlinePosition value="-77"/>
      <underlineThickness value="51"/>
      <isFixedPitch value="0"/>
      <minMemType42 value="0"/>
      <maxMemType42 value="0"/>
      <minMemType1 value="0"/>
      <maxMemType1 value="0"/>
    </post>

    <SVG>
      <svgDoc endGlyphID="2" startGlyphID="2">
        <![CDATA[<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><defs/><g id="glyph2" transform="matrix(6 0 0 6 0 -950)"><path d="M200,100 A100 100 0 1 1 0,100 A100 100 0 1 1 200,100 Z" fill="#F49924"/><path d="M74.545,71.818 A15 21.818 0 1 1 44.545,71.818 A15 21.818 0 1 1 74.545,71.818 Z" fill="#7E4418" id="a"/><use href="#a" x="80.91"/></g></svg>]]>
      </svgDoc>
    </SVG>
  </ttFont>

@anthrotype
Copy link
Member

if you use --color_format=untouchedsvg instead of picosvg then the source SVG are not modified, so if they didn't contain <use> in the first place, they won't after compiling to OT-SVG.

@yisibl
Copy link
Contributor Author

yisibl commented Apr 9, 2021

Well, that's ok, but the position is wrong. I think we still need to use picosvg to adjust the position.(Safari)
image

@anthrotype
Copy link
Member

thanks! we should open a distinct issue for the latter mis-positioning for untouchedsvg output. I can see that our code handling untouchedsvg output is incorrectly adding a translation transform without checking whether the SVG already has a viewBox like in this case.

def _rawsvg_docs(
ttfont: ttLib.TTFont, color_glyphs: Sequence[ColorGlyph]
) -> Sequence[Tuple[str, int, int]]:
doc_list = []
for color_glyph in color_glyphs:
svg = (
SVG.parse(color_glyph.filename)
# dumb sizing isn't useful
.remove_attributes(("width", "height"), inplace=True)
# Firefox likes to render blank if present
.remove_attributes(("enable-background",), inplace=True)
# Map gid => svg doc
.set_attributes((("id", f"glyph{color_glyph.glyph_id}"),))
)
svg.svg_root.attrib[
"transform"
] = f"translate(0, {-color_glyph.ufo.info.unitsPerEm})"
doc_list.append((svg.tostring(), color_glyph.glyph_id, color_glyph.glyph_id))
return doc_list

I think I have a solution.

@anthrotype
Copy link
Member

I created an OT-SVG font from the SVG file posted by @yisibl that reproduces this issue on Safari 14.0.
It contains a single color emoji under the cmap entry for lowercase "a" (for ease of input). I also included a static html file that you can load using python3 -m http.server 8001 then browse to http://localhost:8001

test-ot-svg-safari-use-bug.zip

It looks like this on Safari:

image

On Firefox (v87.0) it looks correctly as expected:

image

The SVG document embedded in the font looks like this:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <defs/>
    <g id="glyph2" transform="matrix(6 0 0 6 37.5 -950)">
        <path d="M200,100 A100 100 0 1 1 0,100 A100 100 0 1 1 200,100 Z" fill="#F49924"/>
        <path d="M74.545,71.818 A15 21.818 0 1 1 44.545,71.818 A15 21.818 0 1 1 74.545,71.818 Z" fill="#7E4418" id="glyph2::1"/>
        <use href="#glyph2::1" x="80.91"/>
    </g>
</svg>

Besides the use of <use> the document is very simple, I don't see anything wrong. I also tried to rename the identifier glyph2::1 to something else that doesn't contain :: or doesn't start with glyph (e.g. "a") but it does not fix the issue.

If I load the SVG document as an SVG in Safari (not as a glyph embedded in OT-SVG font), then it renders correctly even with the <use> element.

So I have to conclude that <use> elements are currently not supported in Safari when they are present in an svg document embedded in OT-SVG font.

@litherum
Copy link

litherum commented Apr 12, 2021

I haven't debugged this, so I don't know if there are multiple problems with this content, but I can say right off the bat that you need to add the xlink namespace, and qualify the href attribute, as per the SVG 1.1 spec. Try this:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
    <defs/>
    <g id="glyph2" transform="matrix(6 0 0 6 37.5 -950)">
        <path d="M200,100 A100 100 0 1 1 0,100 A100 100 0 1 1 200,100 Z" fill="#F49924"/>
        <path d="M74.545,71.818 A15 21.818 0 1 1 44.545,71.818 A15 21.818 0 1 1 74.545,71.818 Z" fill="#7E4418" id="glyph2::1"/>
        <use xlink:href="#glyph2::1" x="80.91"/>
    </g>
</svg>

You can see an example of this working correctly in the SVG 1.1 spec: https://www.w3.org/TR/SVG11/images/struct/Use01.svg

So I have to conclude that elements are currently not supported in Safari when they are present in an svg document embedded in OT-SVG font.

We do support <use> elements in OT-SVG.

anthrotype added a commit that referenced this issue Apr 13, 2021
We were using the unqualified 'href' notation which is only supported in SVG2. For this to work properly on Safari and Adobe apps we need to declar the xlink namespace and qualify the attribute as 'xlink:href'

Fixes #264 and #266

Supersedes googlefonts/picosvg#207 and #270

Many thanks yisibl for helping debugging and fixing this!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants