From 8f0c4a6b250a2afa4d5145bee39adbf443dfcbd8 Mon Sep 17 00:00:00 2001 From: Bernhard Haumacher Date: Sun, 10 May 2020 12:28:42 +0200 Subject: Added documentation to the HmtxTable. --- .../graph/font/typecast/ot/table/HmtxTable.java | 160 +++++++++++++++++++-- 1 file changed, 148 insertions(+), 12 deletions(-) diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/HmtxTable.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/HmtxTable.java index 03633e3e5..86bc29215 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/HmtxTable.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/HmtxTable.java @@ -53,7 +53,82 @@ package jogamp.graph.font.typecast.ot.table; import java.io.DataInput; import java.io.IOException; +import jogamp.graph.font.typecast.ot.Fmt; + /** + * Horizontal Metrics Table + * + *

+ * Glyph metrics used for horizontal text layout include glyph advance widths, + * side bearings and X-direction min and max values (xMin, xMax). These are + * derived using a combination of the glyph outline data ('glyf', 'CFF ' or + * CFF2) and the horizontal metrics table. The horizontal metrics ('hmtx') table + * provides glyph advance widths and left side bearings. + *

+ * + *

+ * In a font with TrueType outline data, the 'glyf' table provides xMin and xMax + * values, but not advance widths or side bearings. The advance width is always + * obtained from the 'hmtx' table. In some fonts, depending on the state of + * flags in the 'head' table, the left side bearings may be the same as the xMin + * values in the 'glyf' table, though this is not true for all fonts. (See the + * description of bit 1 of the {@link HeadTable#getFlags() flags} field in the + * 'head' table.) For this reason, left side bearings are provided in the 'hmtx' + * table. The right side bearing is always derived using advance width and left + * side bearing values from the 'hmtx' table, plus bounding-box information in + * the glyph description — see below for more details. + *

+ * + *

+ * In a variable font with TrueType outline data, the left side bearing value in + * the 'hmtx' table must always be equal to xMin (bit 1 of the 'head' + * {@link HeadTable#getFlags() flags} field must be set). Hence, these values + * can also be derived directly from the 'glyf' table. Note that these values + * apply only to the default instance of the variable font: non-default + * instances may have different side bearing values. These can be derived from + * interpolated “phantom point” coordinates using the 'gvar' table (see below + * for additional details), or by applying variation data in the HVAR table to + * default-instance values from the 'glyf' or 'hmtx' table. + *

+ * + *

+ * In a font with CFF version 1 outline data, the 'CFF ' table does include + * advance widths. These values are used by PostScript processors, but are not + * used in OpenType layout. In an OpenType context, the 'hmtx' table is required + * and must be used for advance widths. Note that fonts in a Font Collection + * file that share a 'CFF ' table may specify different advance widths in + * font-specific 'hmtx' tables for a particular glyph index. Also note that the + * CFF2 table does not include advance widths. In addition, for either CFF or + * CFF2 data, there are no explicit xMin and xMax values; side bearings are + * implicitly contained within the CharString data, and can be obtained from the + * the CFF / CFF2 rasterizer. Some layout engines may use left side bearing + * values in the 'hmtx' table, however; hence, font production tools should + * ensure that the lsb values in the 'hmtx' table match the implicit xMin values + * reflected in the CharString data. In a variable font with CFF2 outline data, + * left side bearing and advance width values for non-default instances should + * be obtained by combining information from the 'hmtx' and HVAR tables. + *

+ * + *

+ * The table uses a longHorMetric record to give the advance width and left side + * bearing of a glyph. Records are indexed by glyph ID. As an optimization, the + * number of records can be less than the number of glyphs, in which case the + * advance width value of the last record applies to all remaining glyph IDs. + * This can be useful in monospaced fonts, or in fonts that have a large number + * of glyphs with the same advance width (provided the glyphs are ordered + * appropriately). The number of longHorMetric records is determined by the + * numberOfHMetrics field in the 'hhea' table. + *

+ * + *

+ * If the longHorMetric array is less than the total number of glyphs, then that + * array is followed by an array for the left side bearing values of the + * remaining glyphs. The number of elements in the left side bearing will be + * derived from numberOfHMetrics plus the numGlyphs field in the 'maxp' table. + *

+ * + * @see "https://docs.microsoft.com/en-us/typography/opentype/spec/hmtx" + * * @author David Schweinsberg */ public class HmtxTable implements Table { @@ -62,11 +137,26 @@ public class HmtxTable implements Table { private short[] _leftSideBearing; private int _length; + /** + * Creates a {@link HmtxTable}. + * + * @param di + * The reader to read from. + * @param length + * The length of the table in bytes. + * @param hhea + * The corresponding {@link HheaTable}. + * @param maxp + * The corresponding {@link MaxpTable}. + */ public HmtxTable( DataInput di, int length, HheaTable hhea, MaxpTable maxp) throws IOException { + + // Paired advance width and left side bearing values for each glyph. + // Records are indexed by glyph ID. _hMetrics = new int[hhea.getNumberOfHMetrics()]; for (int i = 0; i < hhea.getNumberOfHMetrics(); ++i) { _hMetrics[i] = @@ -75,6 +165,9 @@ public class HmtxTable implements Table { | di.readUnsignedByte()<<8 | di.readUnsignedByte(); } + + // Left side bearings for glyph IDs greater than or equal to + // numberOfHMetrics. int lsbCount = maxp.getNumGlyphs() - hhea.getNumberOfHMetrics(); _leftSideBearing = new short[lsbCount]; for (int i = 0; i < lsbCount; ++i) { @@ -88,17 +181,58 @@ public class HmtxTable implements Table { return hmtx; } + /** + * uint16 + * + * Advance width, in font design units. + * + *

+ * The baseline is an imaginary line that is used to ‘guide’ glyphs when + * rendering text. It can be horizontal (e.g., Latin, Cyrillic, Arabic) or + * vertical (e.g., Chinese, Japanese, Mongolian). Moreover, to render text, + * a virtual point, located on the baseline, called the pen position or + * origin, is used to locate glyphs. + *

+ * + *

+ * The distance between two successive pen positions is glyph-specific and + * is called the advance width. Note that its value is always positive, even + * for right-to-left oriented scripts like Arabic. This introduces some + * differences in the way text is rendered. + *

+ * + * @param i + * The glyph index, see {@link GlyfTable#getNumGlyphs()}. + * + * @see "https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html" + */ public int getAdvanceWidth(int i) { if (_hMetrics == null) { return 0; } if (i < _hMetrics.length) { - return _hMetrics[i] >> 16; + return _hMetrics[i] >>> 16; } else { - return _hMetrics[_hMetrics.length - 1] >> 16; + return _hMetrics[_hMetrics.length - 1] >>> 16; } } + /** + * int16 + * + * Glyph left side bearing, in font design units. + * + *

+ * The horizontal distance from the current pen position to the glyph's left + * bbox edge. It is positive for horizontal layouts, and in most cases + * negative for vertical ones. + *

+ * + * @param i + * The glyph index, see {@link GlyfTable#getNumGlyphs()}. + * + * @see "https://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html" + */ public short getLeftSideBearing(int i) { if (_hMetrics == null) { return 0; @@ -110,21 +244,23 @@ public class HmtxTable implements Table { } } + @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("'hmtx' Table - Horizontal Metrics\n---------------------------------\n"); - sb.append("Size = ").append(_length).append(" bytes, ") - .append(_hMetrics.length).append(" entries\n"); + sb.append("'hmtx' Table - Horizontal Metrics\n"); + sb.append("---------------------------------\n"); + sb.append(" Size: ").append(_length).append(" bytes\n"); + sb.append(" Length: ").append(_hMetrics.length).append(" entries\n"); for (int i = 0; i < _hMetrics.length; i++) { - sb.append(" ").append(i) - .append(". advWid: ").append(getAdvanceWidth(i)) - .append(", LSdBear: ").append(getLeftSideBearing(i)) - .append("\n"); + sb.append(" ").append(Fmt.pad(6, i)).append(": "); + sb.append("adv=").append(getAdvanceWidth(i)); + sb.append(", lsb=").append(getLeftSideBearing(i)); + sb.append("\n"); } for (int i = 0; i < _leftSideBearing.length; i++) { - sb.append(" LSdBear ").append(i + _hMetrics.length) - .append(": ").append(_leftSideBearing[i]) - .append("\n"); + sb.append(" ").append(Fmt.pad(6, i + _hMetrics.length)).append(": "); + sb.append("lsb=").append(_leftSideBearing[i]); + sb.append("\n"); } return sb.toString(); } -- cgit v1.2.3