aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/ttLib/tables/S_V_G_.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/fontTools/ttLib/tables/S_V_G_.py')
-rw-r--r--Lib/fontTools/ttLib/tables/S_V_G_.py290
1 files changed, 154 insertions, 136 deletions
diff --git a/Lib/fontTools/ttLib/tables/S_V_G_.py b/Lib/fontTools/ttLib/tables/S_V_G_.py
index 49e98d03..ebc2befd 100644
--- a/Lib/fontTools/ttLib/tables/S_V_G_.py
+++ b/Lib/fontTools/ttLib/tables/S_V_G_.py
@@ -50,148 +50,166 @@ doc_index_entry_format_0 = """
doc_index_entry_format_0Size = sstruct.calcsize(doc_index_entry_format_0)
-
class table_S_V_G_(DefaultTable.DefaultTable):
-
- def decompile(self, data, ttFont):
- self.docList = []
- # Version 0 is the standardized version of the table; and current.
- # https://www.microsoft.com/typography/otspec/svg.htm
- sstruct.unpack(SVG_format_0, data[:SVG_format_0Size], self)
- if self.version != 0:
- log.warning(
- "Unknown SVG table version '%s'. Decompiling as version 0.", self.version)
- # read in SVG Documents Index
- # data starts with the first entry of the entry list.
- pos = subTableStart = self.offsetToSVGDocIndex
- self.numEntries = struct.unpack(">H", data[pos:pos+2])[0]
- pos += 2
- if self.numEntries > 0:
- data2 = data[pos:]
- entries = []
- for i in range(self.numEntries):
- docIndexEntry, data2 = sstruct.unpack2(doc_index_entry_format_0, data2, DocumentIndexEntry())
- entries.append(docIndexEntry)
-
- for entry in entries:
- start = entry.svgDocOffset + subTableStart
- end = start + entry.svgDocLength
- doc = data[start:end]
- compressed = False
- if doc.startswith(b"\x1f\x8b"):
- import gzip
- bytesIO = BytesIO(doc)
- with gzip.GzipFile(None, "r", fileobj=bytesIO) as gunzipper:
- doc = gunzipper.read()
- del bytesIO
- compressed = True
- doc = tostr(doc, "utf_8")
- self.docList.append(
- SVGDocument(doc, entry.startGlyphID, entry.endGlyphID, compressed)
- )
-
- def compile(self, ttFont):
- version = 0
- offsetToSVGDocIndex = SVG_format_0Size # I start the SVGDocIndex right after the header.
- # get SGVDoc info.
- docList = []
- entryList = []
- numEntries = len(self.docList)
- datum = struct.pack(">H",numEntries)
- entryList.append(datum)
- curOffset = len(datum) + doc_index_entry_format_0Size*numEntries
- seenDocs = {}
- allCompressed = getattr(self, "compressed", False)
- for i, doc in enumerate(self.docList):
- if isinstance(doc, (list, tuple)):
- doc = SVGDocument(*doc)
- self.docList[i] = doc
- docBytes = tobytes(doc.data, encoding="utf_8")
- if (allCompressed or doc.compressed) and not docBytes.startswith(b"\x1f\x8b"):
- import gzip
- bytesIO = BytesIO()
- # mtime=0 strips the useless timestamp and makes gzip output reproducible;
- # equivalent to `gzip -n`
- with gzip.GzipFile(None, "w", fileobj=bytesIO, mtime=0) as gzipper:
- gzipper.write(docBytes)
- gzipped = bytesIO.getvalue()
- if len(gzipped) < len(docBytes):
- docBytes = gzipped
- del gzipped, bytesIO
- docLength = len(docBytes)
- if docBytes in seenDocs:
- docOffset = seenDocs[docBytes]
- else:
- docOffset = curOffset
- curOffset += docLength
- seenDocs[docBytes] = docOffset
- docList.append(docBytes)
- entry = struct.pack(">HHLL", doc.startGlyphID, doc.endGlyphID, docOffset, docLength)
- entryList.append(entry)
- entryList.extend(docList)
- svgDocData = bytesjoin(entryList)
-
- reserved = 0
- header = struct.pack(">HLL", version, offsetToSVGDocIndex, reserved)
- data = [header, svgDocData]
- data = bytesjoin(data)
- return data
-
- def toXML(self, writer, ttFont):
- for i, doc in enumerate(self.docList):
- if isinstance(doc, (list, tuple)):
- doc = SVGDocument(*doc)
- self.docList[i] = doc
- attrs = {"startGlyphID": doc.startGlyphID, "endGlyphID": doc.endGlyphID}
- if doc.compressed:
- attrs["compressed"] = 1
- writer.begintag("svgDoc", **attrs)
- writer.newline()
- writer.writecdata(doc.data)
- writer.newline()
- writer.endtag("svgDoc")
- writer.newline()
-
- def fromXML(self, name, attrs, content, ttFont):
- if name == "svgDoc":
- if not hasattr(self, "docList"):
- self.docList = []
- doc = strjoin(content)
- doc = doc.strip()
- startGID = int(attrs["startGlyphID"])
- endGID = int(attrs["endGlyphID"])
- compressed = bool(safeEval(attrs.get("compressed", "0")))
- self.docList.append(SVGDocument(doc, startGID, endGID, compressed))
- else:
- log.warning("Unknown %s %s", name, content)
+ def decompile(self, data, ttFont):
+ self.docList = []
+ # Version 0 is the standardized version of the table; and current.
+ # https://www.microsoft.com/typography/otspec/svg.htm
+ sstruct.unpack(SVG_format_0, data[:SVG_format_0Size], self)
+ if self.version != 0:
+ log.warning(
+ "Unknown SVG table version '%s'. Decompiling as version 0.",
+ self.version,
+ )
+ # read in SVG Documents Index
+ # data starts with the first entry of the entry list.
+ pos = subTableStart = self.offsetToSVGDocIndex
+ self.numEntries = struct.unpack(">H", data[pos : pos + 2])[0]
+ pos += 2
+ if self.numEntries > 0:
+ data2 = data[pos:]
+ entries = []
+ for i in range(self.numEntries):
+ record_data = data2[
+ i
+ * doc_index_entry_format_0Size : (i + 1)
+ * doc_index_entry_format_0Size
+ ]
+ docIndexEntry = sstruct.unpack(
+ doc_index_entry_format_0, record_data, DocumentIndexEntry()
+ )
+ entries.append(docIndexEntry)
+
+ for entry in entries:
+ start = entry.svgDocOffset + subTableStart
+ end = start + entry.svgDocLength
+ doc = data[start:end]
+ compressed = False
+ if doc.startswith(b"\x1f\x8b"):
+ import gzip
+
+ bytesIO = BytesIO(doc)
+ with gzip.GzipFile(None, "r", fileobj=bytesIO) as gunzipper:
+ doc = gunzipper.read()
+ del bytesIO
+ compressed = True
+ doc = tostr(doc, "utf_8")
+ self.docList.append(
+ SVGDocument(doc, entry.startGlyphID, entry.endGlyphID, compressed)
+ )
+
+ def compile(self, ttFont):
+ version = 0
+ offsetToSVGDocIndex = (
+ SVG_format_0Size # I start the SVGDocIndex right after the header.
+ )
+ # get SGVDoc info.
+ docList = []
+ entryList = []
+ numEntries = len(self.docList)
+ datum = struct.pack(">H", numEntries)
+ entryList.append(datum)
+ curOffset = len(datum) + doc_index_entry_format_0Size * numEntries
+ seenDocs = {}
+ allCompressed = getattr(self, "compressed", False)
+ for i, doc in enumerate(self.docList):
+ if isinstance(doc, (list, tuple)):
+ doc = SVGDocument(*doc)
+ self.docList[i] = doc
+ docBytes = tobytes(doc.data, encoding="utf_8")
+ if (allCompressed or doc.compressed) and not docBytes.startswith(
+ b"\x1f\x8b"
+ ):
+ import gzip
+
+ bytesIO = BytesIO()
+ # mtime=0 strips the useless timestamp and makes gzip output reproducible;
+ # equivalent to `gzip -n`
+ with gzip.GzipFile(None, "w", fileobj=bytesIO, mtime=0) as gzipper:
+ gzipper.write(docBytes)
+ gzipped = bytesIO.getvalue()
+ if len(gzipped) < len(docBytes):
+ docBytes = gzipped
+ del gzipped, bytesIO
+ docLength = len(docBytes)
+ if docBytes in seenDocs:
+ docOffset = seenDocs[docBytes]
+ else:
+ docOffset = curOffset
+ curOffset += docLength
+ seenDocs[docBytes] = docOffset
+ docList.append(docBytes)
+ entry = struct.pack(
+ ">HHLL", doc.startGlyphID, doc.endGlyphID, docOffset, docLength
+ )
+ entryList.append(entry)
+ entryList.extend(docList)
+ svgDocData = bytesjoin(entryList)
+
+ reserved = 0
+ header = struct.pack(">HLL", version, offsetToSVGDocIndex, reserved)
+ data = [header, svgDocData]
+ data = bytesjoin(data)
+ return data
+
+ def toXML(self, writer, ttFont):
+ for i, doc in enumerate(self.docList):
+ if isinstance(doc, (list, tuple)):
+ doc = SVGDocument(*doc)
+ self.docList[i] = doc
+ attrs = {"startGlyphID": doc.startGlyphID, "endGlyphID": doc.endGlyphID}
+ if doc.compressed:
+ attrs["compressed"] = 1
+ writer.begintag("svgDoc", **attrs)
+ writer.newline()
+ writer.writecdata(doc.data)
+ writer.newline()
+ writer.endtag("svgDoc")
+ writer.newline()
+
+ def fromXML(self, name, attrs, content, ttFont):
+ if name == "svgDoc":
+ if not hasattr(self, "docList"):
+ self.docList = []
+ doc = strjoin(content)
+ doc = doc.strip()
+ startGID = int(attrs["startGlyphID"])
+ endGID = int(attrs["endGlyphID"])
+ compressed = bool(safeEval(attrs.get("compressed", "0")))
+ self.docList.append(SVGDocument(doc, startGID, endGID, compressed))
+ else:
+ log.warning("Unknown %s %s", name, content)
class DocumentIndexEntry(object):
- def __init__(self):
- self.startGlyphID = None # USHORT
- self.endGlyphID = None # USHORT
- self.svgDocOffset = None # ULONG
- self.svgDocLength = None # ULONG
+ def __init__(self):
+ self.startGlyphID = None # USHORT
+ self.endGlyphID = None # USHORT
+ self.svgDocOffset = None # ULONG
+ self.svgDocLength = None # ULONG
- def __repr__(self):
- return "startGlyphID: %s, endGlyphID: %s, svgDocOffset: %s, svgDocLength: %s" % (self.startGlyphID, self.endGlyphID, self.svgDocOffset, self.svgDocLength)
+ def __repr__(self):
+ return (
+ "startGlyphID: %s, endGlyphID: %s, svgDocOffset: %s, svgDocLength: %s"
+ % (self.startGlyphID, self.endGlyphID, self.svgDocOffset, self.svgDocLength)
+ )
@dataclass
class SVGDocument(Sequence):
- data: str
- startGlyphID: int
- endGlyphID: int
- compressed: bool = False
-
- # Previously, the SVG table's docList attribute contained a lists of 3 items:
- # [doc, startGlyphID, endGlyphID]; later, we added a `compressed` attribute.
- # For backward compatibility with code that depends of them being sequences of
- # fixed length=3, we subclass the Sequence abstract base class and pretend only
- # the first three items are present. 'compressed' is only accessible via named
- # attribute lookup like regular dataclasses: i.e. `doc.compressed`, not `doc[3]`
- def __getitem__(self, index):
- return astuple(self)[:3][index]
-
- def __len__(self):
- return 3
+ data: str
+ startGlyphID: int
+ endGlyphID: int
+ compressed: bool = False
+
+ # Previously, the SVG table's docList attribute contained a lists of 3 items:
+ # [doc, startGlyphID, endGlyphID]; later, we added a `compressed` attribute.
+ # For backward compatibility with code that depends of them being sequences of
+ # fixed length=3, we subclass the Sequence abstract base class and pretend only
+ # the first three items are present. 'compressed' is only accessible via named
+ # attribute lookup like regular dataclasses: i.e. `doc.compressed`, not `doc[3]`
+ def __getitem__(self, index):
+ return astuple(self)[:3][index]
+
+ def __len__(self):
+ return 3