aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernhard Haumacher <[email protected]>2020-05-10 20:46:02 +0200
committerSven Göthel <[email protected]>2024-02-03 02:00:53 +0100
commitadc90be6effd090f217e2613d0dab13f9a1ad7c9 (patch)
tree4ceb76c4e271b62a2682c95826292ed633568e83
parent2a23fede0f8ee99ed958f0f547f2558da7662cd9 (diff)
Added support for reading the SVG table. # Conflicts: # src/jogl/classes/jogamp/graph/font/typecast/ot/TTFont.java # src/jogl/classes/jogamp/graph/font/typecast/ot/table/Table.java
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/ot/TTFont.java29
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/ot/table/SVGTable.java276
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/ot/table/Table.java77
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/ot/table/TableDirectory.java29
4 files changed, 363 insertions, 48 deletions
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/TTFont.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/TTFont.java
index 90ddda48a..ee3e46000 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/ot/TTFont.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/TTFont.java
@@ -32,6 +32,7 @@ import jogamp.graph.font.typecast.ot.table.GlyfTable;
import jogamp.graph.font.typecast.ot.table.HdmxTable;
import jogamp.graph.font.typecast.ot.table.KernTable;
import jogamp.graph.font.typecast.ot.table.LocaTable;
+import jogamp.graph.font.typecast.ot.table.SVGTable;
import jogamp.graph.font.typecast.ot.table.Table;
import jogamp.graph.font.typecast.ot.table.VdmxTable;
@@ -42,6 +43,7 @@ public class TTFont extends OTFont {
private KernTable _kern;
private HdmxTable _hdmx;
private VdmxTable _vdmx;
+ private SVGTable _svg;
private static TableDirectory readTableDir(final DataInputStream dis, final int directoryOffset) throws IOException {
// Load the table directory
@@ -120,12 +122,19 @@ public class TTFont extends OTFont {
// 'loca' is required by 'glyf'
int length = seekTable(dis, tablesOrigin, Table.loca);
- LocaTable loca = new LocaTable(dis, length, this.getHeadTable(), this.getMaxpTable());
-
- // If this is a TrueType outline, then we'll have at least the
- // 'glyf' table (along with the 'loca' table)
- length = seekTable(dis, tablesOrigin, Table.glyf);
- _glyf = new GlyfTable(dis, length, this.getMaxpTable(), loca);
+ if (length > 0) {
+ LocaTable loca = new LocaTable(dis, length, this.getHeadTable(), this.getMaxpTable());
+
+ // If this is a TrueType outline, then we'll have at least the
+ // 'glyf' table (along with the 'loca' table)
+ length = seekTable(dis, tablesOrigin, Table.glyf);
+ _glyf = new GlyfTable(dis, length, this.getMaxpTable(), loca);
+ }
+
+ length = seekTable(dis, tablesOrigin, Table.svg);
+ if (length > 0) {
+ _svg = new SVGTable(dis);
+ }
length = seekTable(dis, tablesOrigin, Table.gasp);
if (length > 0) {
@@ -151,6 +160,13 @@ public class TTFont extends OTFont {
public GlyfTable getGlyfTable() {
return _glyf;
}
+
+ /**
+ * Optional {@link SVGTable}.
+ */
+ public SVGTable getSvgTable() {
+ return _svg;
+ }
public GaspTable getGaspTable() {
return _gasp;
@@ -188,6 +204,7 @@ public class TTFont extends OTFont {
public void dumpTo(Writer out) throws IOException {
super.dumpTo(out);
dump(out, getGlyfTable());
+ dump(out, getSvgTable());
dump(out, getGaspTable());
dump(out, getKernTable());
dump(out, getHdmxTable());
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/SVGTable.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/SVGTable.java
new file mode 100644
index 000000000..c85661dc2
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/SVGTable.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2020 Business Operation Systems GmbH. All Rights Reserved.
+ */
+package jogamp.graph.font.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * The SVG (Scalable Vector Graphics) table
+ *
+ * <p>
+ * This table contains SVG descriptions for some or all of the glyphs in the font.
+ * </p>
+ *
+ * @see "https://docs.microsoft.com/en-us/typography/opentype/spec/svg"
+ *
+ * @author <a href="mailto:[email protected]">Bernhard Haumacher</a>
+ */
+public class SVGTable implements Table {
+
+ /**
+ * @see #getVersion()
+ */
+ public static final int VERSION = 0;
+
+ /**
+ * @see #getVersion()
+ */
+ private int _version = VERSION;
+
+ /**
+ * @see #getDocumentRecords()
+ */
+ private SVGDocumentRecord[] _documentRecords;
+
+ /**
+ * Creates a {@link SVGTable}.
+ *
+ * @param di The reader to read from.
+ */
+ public SVGTable(DataInput di) throws IOException {
+ _version = di.readUnsignedShort();
+
+ // Offset to the SVG Document List, from the start of the SVG table.
+ // Must be non-zero.
+ int offsetToSVGDocumentList = di.readInt();
+ di.skipBytes(offsetToSVGDocumentList - 6);
+
+ // SVG Document List starts here.
+ int offset = 0;
+
+ // uint16 Number of SVG document records. Must be non-zero.
+ int numEntries = di.readUnsignedShort();
+ offset += 2;
+
+ _documentRecords = new SVGDocumentRecord[numEntries];
+ for (int n = 0; n < numEntries; n++) {
+ _documentRecords[n] = new SVGDocumentRecord(di);
+ }
+ offset += numEntries * 12;
+
+ SVGDocumentRecord[] recordsInOffsetOrder = new SVGDocumentRecord[numEntries];
+ System.arraycopy(_documentRecords, 0, recordsInOffsetOrder, 0, numEntries);
+ Arrays.sort(recordsInOffsetOrder, (a, b) -> Integer.compare(a.getSvgDocOffset(), b.getSvgDocOffset()));
+
+ int lastOffset = 0;
+ for (int n = 0; n < numEntries; n++) {
+ SVGDocumentRecord record = recordsInOffsetOrder[n];
+
+ int docOffset = record.getSvgDocOffset();
+ if (docOffset == lastOffset) {
+ // Pointing to the same document.
+ record.setDocument(recordsInOffsetOrder[n - 1].getDocument());
+ } else {
+ int skip = docOffset - offset;
+ assert skip >= 0;
+ di.skipBytes(skip);
+ offset = docOffset;
+ }
+ lastOffset = offset;
+ record.readDoc(di);
+ offset += record.getSvgDocLength();
+ }
+ }
+
+ /**
+ * Records must be sorted in order of increasing startGlyphID. For any given
+ * record, the startGlyphID must be less than or equal to the endGlyphID of
+ * that record, and also must be greater than the endGlyphID of any previous
+ * record.
+ *
+ * <p>
+ * Note: Two or more records can point to the same SVG document. In this
+ * way, a single SVG document can provide glyph descriptions for
+ * discontinuous glyph ID ranges.
+ * </p>
+ */
+ public SVGDocumentRecord[] getDocumentRecords() {
+ return _documentRecords;
+ }
+
+ /**
+ * uint16 version Table version (starting at 0). Set to {@link #VERSION}.
+ */
+ public int getVersion() {
+ return _version;
+ }
+
+ @Override
+ public int getType() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "SVG Table\n" +
+ "---------\n" +
+ " Version: " + getVersion() + "\n" +
+ " Number of records: " + getDocumentRecords().length;
+ }
+
+ @Override
+ public void dump(Writer out) throws IOException {
+ Table.super.dump(out);
+
+ for (SVGDocumentRecord record : getDocumentRecords()) {
+ out.write("\n\n");
+ out.write(record.toString());
+ }
+ }
+
+ /**
+ * Each SVG document record specifies a range of glyph IDs (from
+ * startGlyphID to endGlyphID, inclusive), and the location of its
+ * associated SVG document in the SVG table.
+ */
+ public static class SVGDocumentRecord {
+
+ /**
+ * @see #getStartGlyphID()
+ */
+ private int _startGlyphID;
+
+ /**
+ * @see #getEndGlyphID()
+ */
+ private int _endGlyphID;
+
+ /**
+ * @see #getSvgDocOffset()
+ */
+ private int _svgDocOffset;
+
+ /**
+ * @see #getSvgDocLength()
+ */
+ private int _svgDocLength;
+
+ private String _document;
+
+ /**
+ * Creates a {@link SVGDocumentRecord}.
+ *
+ * @param di
+ */
+ public SVGDocumentRecord(DataInput di) throws IOException {
+ _startGlyphID = di.readUnsignedShort();
+ _endGlyphID = di.readUnsignedShort();
+ _svgDocOffset = di.readInt();
+ _svgDocLength = di.readInt();
+ }
+
+ /**
+ * Reads the SVG document from the given reader.
+ */
+ public void readDoc(DataInput di) throws IOException {
+ byte[] docData = new byte[getSvgDocLength()];
+ di.readFully(docData);
+
+ if (docData[0] == 0x1F && docData[1] == 0x8B && docData[2] == 0x08) {
+ // Gzip encoded document.
+ try (GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(docData))) {
+ readDoc(in);
+ }
+ } else {
+ try (InputStream in = new ByteArrayInputStream(docData)) {
+ readDoc(in);
+ }
+ }
+ }
+
+ private void readDoc(InputStream in) throws IOException {
+ StringBuilder doc = new StringBuilder();
+ char[] buffer = new char[4096];
+ try (InputStreamReader r = new InputStreamReader(in, Charset.forName("utf-8"))) {
+ while (true) {
+ int direct = r.read(buffer);
+ if (direct < 0) {
+ break;
+ }
+ doc.append(buffer, 0, direct);
+ }
+ }
+
+ _document = doc.toString();
+ }
+
+ /**
+ * uint16
+ *
+ * The first glyph ID for the range covered by this record.
+ */
+ public int getStartGlyphID() {
+ return _startGlyphID;
+ }
+
+ /**
+ * uint16
+ *
+ * The last glyph ID for the range covered by this record.
+ */
+ public int getEndGlyphID() {
+ return _endGlyphID;
+ }
+
+ /**
+ * Offset32
+ *
+ * Offset from the beginning of the SVGDocumentList to an SVG document. Must be non-zero.
+ */
+ public int getSvgDocOffset() {
+ return _svgDocOffset;
+ }
+
+ /**
+ * uint32
+ *
+ * Length of the SVG document data. Must be non-zero.
+ */
+ public int getSvgDocLength() {
+ return _svgDocLength;
+ }
+
+ /**
+ * The SVG document as XML string.
+ */
+ public String getDocument() {
+ return _document;
+ }
+
+ /**
+ * @see #getDocument()
+ */
+ public void setDocument(String document) {
+ _document = document;
+ }
+
+ @Override
+ public String toString() {
+ return
+ " SVG document record\n" +
+ " -------------------\n" +
+ " startGlyphID: " + getStartGlyphID() + "\n" +
+ " endGlyphID: " + getEndGlyphID() + "\n" +
+ " svg: " + getDocument();
+ }
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/Table.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/Table.java
index 837411d83..499fa7492 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/Table.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/Table.java
@@ -26,44 +26,45 @@ import java.io.Writer;
public interface Table {
// Table constants
- static final int BASE = 0x42415345; // Baseline data [OpenType]
- static final int CFF = 0x43464620; // PostScript font program (compact font format) [PostScript]
- static final int COLR = 0x434f4c52; // Color Table
- static final int CPAL = 0x4350414c; // Color Palette Table
- static final int DSIG = 0x44534947; // Digital signature
- static final int EBDT = 0x45424454; // Embedded bitmap data
- static final int EBLC = 0x45424c43; // Embedded bitmap location data
- static final int EBSC = 0x45425343; // Embedded bitmap scaling data
- static final int GDEF = 0x47444546; // Glyph definition data [OpenType]
- static final int GPOS = 0x47504f53; // Glyph positioning data [OpenType]
- static final int GSUB = 0x47535542; // Glyph substitution data [OpenType]
- static final int JSTF = 0x4a535446; // Justification data [OpenType]
- static final int LTSH = 0x4c545348; // Linear threshold table
- static final int MMFX = 0x4d4d4658; // Multiple master font metrics [PostScript]
- static final int MMSD = 0x4d4d5344; // Multiple master supplementary data [PostScript]
- static final int OS_2 = 0x4f532f32; // OS/2 and Windows specific metrics [r]
- static final int PCLT = 0x50434c54; // PCL5
- static final int VDMX = 0x56444d58; // Vertical Device Metrics table
- static final int cmap = 0x636d6170; // character to glyph mapping [r]
- static final int cvt = 0x63767420; // Control Value Table
- static final int fpgm = 0x6670676d; // font program
- static final int fvar = 0x66766172; // Apple's font variations table [PostScript]
- static final int gasp = 0x67617370; // grid-fitting and scan conversion procedure (grayscale)
- static final int glyf = 0x676c7966; // glyph data [r]
- static final int hdmx = 0x68646d78; // horizontal device metrics
- static final int head = 0x68656164; // font header [r]
- static final int hhea = 0x68686561; // horizontal header [r]
- static final int hmtx = 0x686d7478; // horizontal metrics [r]
- static final int kern = 0x6b65726e; // kerning
- static final int loca = 0x6c6f6361; // index to location [r]
- static final int maxp = 0x6d617870; // maximum profile [r]
- static final int name = 0x6e616d65; // naming table [r]
- static final int prep = 0x70726570; // CVT Program
- static final int post = 0x706f7374; // PostScript information [r]
- static final int sbix = 0x73626978; // Extended Bitmaps
- static final int vhea = 0x76686561; // Vertical Metrics header
- static final int vmtx = 0x766d7478; // Vertical Metrics
-
+ int BASE = 0x42415345; // Baseline data [OpenType]
+ int CFF = 0x43464620; // PostScript font program (compact font format) [PostScript]
+ int COLR = 0x434f4c52; // Color Table
+ int CPAL = 0x4350414c; // Color Palette Table
+ int DSIG = 0x44534947; // Digital signature
+ int EBDT = 0x45424454; // Embedded bitmap data
+ int EBLC = 0x45424c43; // Embedded bitmap location data
+ int EBSC = 0x45425343; // Embedded bitmap scaling data
+ int GDEF = 0x47444546; // Glyph definition data [OpenType]
+ int GPOS = 0x47504f53; // Glyph positioning data [OpenType]
+ int GSUB = 0x47535542; // Glyph substitution data [OpenType]
+ int JSTF = 0x4a535446; // Justification data [OpenType]
+ int LTSH = 0x4c545348; // Linear threshold table
+ int MMFX = 0x4d4d4658; // Multiple master font metrics [PostScript]
+ int MMSD = 0x4d4d5344; // Multiple master supplementary data [PostScript]
+ int OS_2 = 0x4f532f32; // OS/2 and Windows specific metrics [r]
+ int PCLT = 0x50434c54; // PCL5
+ int VDMX = 0x56444d58; // Vertical Device Metrics table
+ int cmap = 0x636d6170; // character to glyph mapping [r]
+ int cvt = 0x63767420; // Control Value Table
+ int fpgm = 0x6670676d; // font program
+ int fvar = 0x66766172; // Apple's font variations table [PostScript]
+ int gasp = 0x67617370; // grid-fitting and scan conversion procedure (grayscale)
+ int glyf = 0x676c7966; // glyph data [r]
+ int hdmx = 0x68646d78; // horizontal device metrics
+ int head = 0x68656164; // font header [r]
+ int hhea = 0x68686561; // horizontal header [r]
+ int hmtx = 0x686d7478; // horizontal metrics [r]
+ int kern = 0x6b65726e; // kerning
+ int loca = 0x6c6f6361; // index to location [r]
+ int maxp = 0x6d617870; // maximum profile [r]
+ int name = 0x6e616d65; // naming table [r]
+ int prep = 0x70726570; // CVT Program
+ int post = 0x706f7374; // PostScript information [r]
+ int sbix = 0x73626978; // Extended Bitmaps
+ int vhea = 0x76686561; // Vertical Metrics header
+ int vmtx = 0x766d7478; // Vertical Metrics
+ int svg = TableDirectory.fromStringTag("SVG "); // SVG outlines
+
/**
* The type code of this {@link Table}.
*/
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/TableDirectory.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/TableDirectory.java
index cd4b0f462..a6ea4df31 100644
--- a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/TableDirectory.java
+++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/TableDirectory.java
@@ -92,10 +92,8 @@ public class TableDirectory {
}
String getTagAsString() {
- return String.valueOf((char) ((_tag >> 24) & 0xff)) +
- (char) ((_tag >> 16) & 0xff) +
- (char) ((_tag >> 8) & 0xff) +
- (char) ((_tag) & 0xff);
+ int tag = _tag;
+ return TableDirectory.toStringTag(tag);
}
@Override
@@ -174,4 +172,27 @@ public class TableDirectory {
}
return sb.toString();
}
+
+ /**
+ * Converts a {@link Table} tag back to {@link String}.
+ */
+ public static String toStringTag(int tag) {
+ return String.valueOf(
+ (char) ((tag >> 24) & 0xff)) +
+ (char) ((tag >> 16) & 0xff) +
+ (char) ((tag >> 8) & 0xff) +
+ (char) (tag & 0xff);
+ }
+
+ /**
+ * Converts a {@link Table} tag {@link String} to an ID.
+ */
+ public static int fromStringTag(String tag) {
+ assert tag.length() == 4;
+ return
+ ((tag.charAt(0) & 0xFF) << 24) |
+ ((tag.charAt(1) & 0xFF) << 16) |
+ ((tag.charAt(2) & 0xFF) << 8) |
+ (tag.charAt(3) & 0xff);
+ }
}