Skip to content

Commit

Permalink
Merge pull request #1031 from googlefonts/clipboard-fix
Browse files Browse the repository at this point in the history
Clipboard fix for invalid input
  • Loading branch information
justvanrossum authored Dec 16, 2023
2 parents dcbfded + e5766b9 commit c788954
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 19 deletions.
34 changes: 23 additions & 11 deletions src/fontra/core/clipboard.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
from xml.etree.ElementTree import ParseError

from fontTools.pens.boundsPen import ControlBoundsPen
from fontTools.pens.pointPen import GuessSmoothPointPen, SegmentToPointPen
from fontTools.pens.recordingPen import RecordingPen
from fontTools.pens.transformPen import TransformPointPen
from fontTools.svgLib import SVGPath
from fontTools.ufoLib.errors import GlifLibError
from fontTools.ufoLib.glifLib import readGlyphFromString, writeGlyphToString

from ..backends.designspace import UFOGlyph, populateUFOLayerGlyph, readGlyphOrCreate
from .classes import StaticGlyph
from .path import PackedPathPointPen


def parseClipboard(data):
def parseClipboard(data: str) -> StaticGlyph | None:
if "<svg" in data:
return parseSVG(data)
if "<?xml" in data and "<glyph " in data:
return parseGLIF(data)
return None


def parseSVG(data):
data = data.encode("utf-8")
svgPath = SVGPath.fromstring(data, transform=(1, 0, 0, -1, 0, 0))
def parseSVG(data: str) -> StaticGlyph | None:
try:
svgPath = SVGPath.fromstring(
data.encode("utf-8"), transform=(1, 0, 0, -1, 0, 0)
)
except ParseError:
return None
recPen = RecordingPen()
svgPath.draw(recPen)
boundsPen = ControlBoundsPen(None)
Expand All @@ -36,20 +43,25 @@ def parseSVG(data):
return StaticGlyph(path=pen.getPath(), xAdvance=xMax)


def parseGLIF(data):
def parseGLIF(data: str) -> StaticGlyph | None:
pen = PackedPathPointPen()
ufoGlyph = UFOGlyph()
readGlyphFromString(
data,
glyphObject=ufoGlyph,
pointPen=pen,
)
try:
readGlyphFromString(
data,
glyphObject=ufoGlyph,
pointPen=pen,
)
except GlifLibError:
return None
return StaticGlyph(
path=pen.getPath(), components=pen.components, xAdvance=ufoGlyph.width
)


def serializeStaticGlyphAsGLIF(glyphName, staticGlyph, unicodes):
def serializeStaticGlyphAsGLIF(
glyphName: str, staticGlyph: StaticGlyph, unicodes: list[int]
) -> str:
layerGlyph = readGlyphOrCreate({}, glyphName, unicodes)
drawPointsFunc = populateUFOLayerGlyph(layerGlyph, staticGlyph)
return writeGlyphToString(glyphName, layerGlyph, drawPointsFunc, validate=False)
16 changes: 8 additions & 8 deletions test-py/test_clipboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"inputData, expectedResult",
[
("dasasdad", None), # unparsable
("<svg xxxx", None), # unparsable
("<?xml xxxx <glyph ", None), # unparsable
(
'<svg xmlns="http://www.w3.org/2000/svg" width="50" '
'height="120" viewBox="60 0 50 120">'
Expand Down Expand Up @@ -68,10 +70,8 @@
),
],
)
def test_parseClipboard(inputData, expectedResult):
result = parseClipboard(inputData)
if result is not None:
result = result
def test_parseClipboard(inputData: str, expectedResult: StaticGlyph):
result: StaticGlyph | None = parseClipboard(inputData)
assert expectedResult == result


Expand Down Expand Up @@ -113,8 +113,8 @@ def test_parseClipboard(inputData, expectedResult):
),
],
)
def test_serializeStaticGlyphAsGLIF(glyphName, glyph, unicodes, expectedResult):
result = serializeStaticGlyphAsGLIF(glyphName, glyph, unicodes)
if result is not None:
result = result
def test_serializeStaticGlyphAsGLIF(
glyphName: str, glyph: StaticGlyph, unicodes: list[int], expectedResult: str
):
result: str = serializeStaticGlyphAsGLIF(glyphName, glyph, unicodes)
assert expectedResult == result

0 comments on commit c788954

Please sign in to comment.