diff options
author | Sven Gothel <[email protected]> | 2023-08-28 22:57:53 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-08-28 22:57:53 +0200 |
commit | 920e529516bb264f04138ed1caca80d4925e3773 (patch) | |
tree | 498bce9425f880cab2cd36b4251eaa4e231e912c /src/jogl/classes/jogamp/graph/font | |
parent | 733cc5272cfed10fa07b707e29fd756f44581508 (diff) |
Graph Font + Glyph: More robust detetection and API definition of non-contour/whitespace Glyphs (detect and allow to skip 'em)
We also drop shapes for both, but for id 0 (unknown).
Diffstat (limited to 'src/jogl/classes/jogamp/graph/font')
-rw-r--r-- | src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java | 99 | ||||
-rw-r--r-- | src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java | 65 |
2 files changed, 109 insertions, 55 deletions
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java index ce490bdf0..8bc832633 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java @@ -48,9 +48,10 @@ import jogamp.graph.font.typecast.ot.table.KernSubtableFormat0; import jogamp.graph.font.typecast.ot.table.KernTable; import jogamp.graph.font.typecast.ot.table.KerningPair; import jogamp.graph.font.typecast.ot.table.PostTable; +import jogamp.opengl.Debug; class TypecastFont implements Font { - static final boolean DEBUG = false; + private static final boolean DEBUG = Debug.debug("graph.font.Font"); // private final OTFontCollection fontset; /* pp */ final TTFont font; @@ -203,34 +204,36 @@ class TypecastFont implements Font { } else { glyph_name = ""; } + final boolean isUndefined = Glyph.ID_UNKNOWN == glyph_id || null == glyph || TypecastGlyph.isUndefName(glyph_name); final int glyph_height = metrics.getAscentFU() - metrics.getDescentFU(); final int glyph_advance; final int glyph_leftsidebearings; + final boolean isWhitespace; final AABBox glyph_bbox; final OutlineShape shape; - final boolean isWhiteSpace; if( null != glyph ) { glyph_advance = glyph.getAdvanceWidth(); glyph_leftsidebearings = glyph.getLeftSideBearing(); final AABBox sb = glyph.getBBox(); - final OutlineShape s = TypecastRenderer.buildShape(metrics.getUnitsPerEM(), glyph); - if( 0 < s.getVertexCount() ) { + final OutlineShape os = TypecastRenderer.buildShape(metrics.getUnitsPerEM(), glyph); + if( 0 < os.getVertexCount() ) { + // Case 1: Either valid contour glyph, undefined or a whitespace (Case 2 with zero-area shape) + isWhitespace = isUndefined ? false : os.getBounds().hasZero2DArea(); glyph_bbox = sb; - shape = s; - isWhiteSpace = false; + shape = ( !isWhitespace && !isUndefined ) || Glyph.ID_UNKNOWN == glyph_id ? os : null; } else { - // non-contour glyph -> whitespace + // Case 2: Non-contour glyph -> whitespace or undefined + isWhitespace = !isUndefined; glyph_bbox = new AABBox(0f,0f,0f, glyph_advance, glyph_height, 0f); - shape = TypecastRenderer.buildEmptyShape(metrics.getUnitsPerEM(), glyph_bbox); - isWhiteSpace = true; + shape = Glyph.ID_UNKNOWN == glyph_id ? TypecastRenderer.buildEmptyShape(metrics.getUnitsPerEM(), glyph_bbox) : null; } } else { - // non-contour glyph -> whitespace + // Case 3: Non-contour glyph -> undefined glyph_advance = getAdvanceWidthFU(glyph_id); glyph_leftsidebearings = 0; + isWhitespace = false; glyph_bbox = new AABBox(0f,0f,0f, glyph_advance, glyph_height, 0f); - shape = TypecastRenderer.buildEmptyShape(metrics.getUnitsPerEM(), glyph_bbox); - isWhiteSpace = true; + shape = Glyph.ID_UNKNOWN == glyph_id ? TypecastRenderer.buildEmptyShape(metrics.getUnitsPerEM(), glyph_bbox) : null; } KernSubtable kernSub = null; { @@ -239,8 +242,9 @@ class TypecastFont implements Font { kernSub = kern.getSubtable0(); } } - result = new TypecastGlyph(this, glyph_id, glyph_name, glyph_bbox, glyph_advance, glyph_leftsidebearings, kernSub, shape, isWhiteSpace); - if(DEBUG) { + result = new TypecastGlyph(this, glyph_id, glyph_name, glyph_bbox, glyph_advance, glyph_leftsidebearings, kernSub, shape, + isUndefined, isWhitespace); + if( DEBUG || TypecastRenderer.DEBUG ) { System.err.println("New glyph: " + glyph_id + "/'"+glyph_name+"', shape " + (null != shape)); System.err.println(" tc_glyph "+glyph); System.err.println(" glyph "+result); @@ -340,22 +344,24 @@ class TypecastFont implements Font { temp1.setToIdentity(); final int glyph_id = getGlyphID(character); final Font.Glyph glyph = getGlyph(glyph_id); - final OutlineShape glyphShape = glyph.getShape(); - if( null == glyphShape ) { // also covers 'space' and all non-contour symbols + if( glyph.isUndefined() ) { + // break kerning, drop undefined + advanceTotal += glyph.getAdvanceFU(); + left_glyph = null; + } else if( glyph.isWhitespace() ) { + // break kerning, but include its bounding box space + left_glyph = null; + temp1.translate(advanceTotal, y, temp2); + res.resize(temp1.transform(glyph.getBoundsFU(), temp_box)); + advanceTotal += glyph.getAdvanceFU(); + } else { + // regular contour + if( null != left_glyph ) { + advanceTotal += left_glyph.getKerningFU(glyph_id); + } + temp1.translate(advanceTotal, y, temp2); + res.resize(temp1.transform(glyph.getBoundsFU(), temp_box)); advanceTotal += glyph.getAdvanceFU(); - left_glyph = null; // break kerning - continue; - } else if( glyph.isWhiteSpace() ) { // covers 'space' and all non-contour symbols - left_glyph = null; // break kerning - } - if( null != left_glyph ) { - advanceTotal += left_glyph.getKerningFU(glyph_id); - } - temp1.translate(advanceTotal, y, temp2); - res.resize(temp1.transform(glyph.getBoundsFU(), temp_box)); - - advanceTotal += glyph.getAdvanceFU(); - if( !glyph.isWhiteSpace() ) { left_glyph = glyph; } } @@ -421,23 +427,26 @@ class TypecastFont implements Font { final int glyph_id = getGlyphID(character); final Font.Glyph glyph = getGlyph(glyph_id); - final OutlineShape glyphShape = glyph.getShape(); - - if( null == glyphShape ) { // also covers 'space' and all non-contour symbols + if( glyph.isUndefined() ) { + // break kerning, drop undefined + advanceTotal += glyph.getAdvance(); + left_glyph = null; + } else if( glyph.isWhitespace() ) { + // break kerning, but include its bounding box space and visit the visitor + left_glyph = null; + temp1.translate(advanceTotal, y, temp2); + res.resize(temp1.transform(glyph.getBounds(), temp_box)); + visitor.visit(character, glyph, temp1); + advanceTotal += glyph.getAdvance(); + } else { + // regular contour + if( null != left_glyph ) { + advanceTotal += left_glyph.getKerning(glyph_id); + } + temp1.translate(advanceTotal, y, temp2); + res.resize(temp1.transform(glyph.getShape().getBounds(), temp_box)); + visitor.visit(character, glyph, temp1); advanceTotal += glyph.getAdvance(); - left_glyph = null; // break kerning - continue; - } else if( glyph.isWhiteSpace() ) { // covers 'space' and all non-contour symbols - left_glyph = null; // break kerning - } - if( null != left_glyph ) { - advanceTotal += left_glyph.getKerning(glyph_id); - } - temp1.translate(advanceTotal, y, temp2); - res.resize(temp1.transform(glyphShape.getBounds(), temp_box)); - visitor.visit(character, glyph, temp1); - advanceTotal += glyph.getAdvance(); - if( !glyph.isWhiteSpace() ) { left_glyph = glyph; } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java index d851efc3e..3ace5c480 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java @@ -39,6 +39,25 @@ public final class TypecastGlyph implements Font.Glyph { public static final short INVALID_ID = (short)((1 << 16) - 1); public static final short MAX_ID = (short)((1 << 16) - 2); + private static final String dot_undef_NAME = ".notdef"; + private static final String NULL_NAME = "NULL"; + private static final String null_NAME = "null"; + private static final String dot_null_NAME = ".null"; + + /* pp */ static final boolean isUndefName(final String name) { + if( null != name ) { + if( TypecastGlyph.dot_undef_NAME.equals(name) ) { + return true; + } else if( TypecastGlyph.NULL_NAME.equals(name) ) { + return true; + } else if( TypecastGlyph.null_NAME.equals(name) ) { + return true; + } else if( TypecastGlyph.dot_null_NAME.equals(name) ) { + return true; + } + } + return false; + } private static int[][] growPairArray(final int[][] src) { final int length = src.length; @@ -66,7 +85,8 @@ public final class TypecastGlyph implements Font.Glyph { private final int id; private final String name; - private final boolean isWhiteSpace; + private final boolean isUndefined; + private final boolean isWhitespace; private final TypecastFont font; private final AABBox bbox; // in font-units @@ -90,10 +110,12 @@ public final class TypecastGlyph implements Font.Glyph { */ protected TypecastGlyph(final TypecastFont font, final int id, final String name, final AABBox bbox, final int advance, final int leftSideBearings, - final KernSubtable kernSub, final OutlineShape shape, final boolean isWhiteSpace) { + final KernSubtable kernSub, final OutlineShape shape, + final boolean isUndefined, final boolean isWhiteSpace) { this.id = id; this.name = name; - this.isWhiteSpace = isWhiteSpace; + this.isUndefined = isUndefined; + this.isWhitespace = isWhiteSpace; this.font = font; this.bbox = bbox; this.advance = advance; @@ -139,10 +161,13 @@ public final class TypecastGlyph implements Font.Glyph { public final String getName() { return name; } @Override - public final boolean isWhiteSpace() { return this.isWhiteSpace; } + public final boolean isWhitespace() { return this.isWhitespace; } + + @Override + public final boolean isUndefined() { return this.isUndefined; } @Override - public final boolean isUndefined() { return name == ".notdef"; } + public final boolean isNonContour() { return isUndefined() || isWhitespace(); } @Override public final AABBox getBoundsFU() { return bbox; } @@ -232,21 +257,41 @@ public final class TypecastGlyph implements Font.Glyph { @Override public String toString() { final StringBuilder sb = new StringBuilder(); - final String ws_s = isWhiteSpace() ? ", ws" : ""; - sb.append("Glyph[id ").append(id).append(" '").append(name).append("'").append(ws_s) + final String contour_s; + if( isNonContour() ) { + final String ws_s = isWhitespace() ? "whitespace" : ""; + final String undef_s = isUndefined() ? "undefined" : ""; + contour_s = "non-cont("+ws_s+undef_s+")"; + } else { + contour_s = "contour"; + } + final String name_s = null != name ? name : ""; + final String shape_s = null != shape ? "shape "+shape.getVertexCount()+"v" : "shape null"; + sb.append("Glyph[id ").append(id).append(" '").append(name_s).append("', ").append(contour_s) + .append(", ").append(shape_s) .append(", advance ").append(getAdvanceFU()) .append(", leftSideBearings ").append(getLeftSideBearingsFU()) .append(", kerning[size ").append(kerning.length).append(", horiz ").append(this.isKerningHorizontal()).append(", cross ").append(this.isKerningCrossstream()).append("]") - .append(", shape ").append(null != shape).append("]"); + .append("]"); return sb.toString(); } @Override public String fullString() { final PostTable post = font.getPostTable(); - final String glyph_name = null != post ? post.getGlyphName(id) : "n/a"; final StringBuilder sb = new StringBuilder(); - sb.append("Glyph id ").append(id).append(" '").append(glyph_name).append("'") + final String contour_s; + if( isNonContour() ) { + final String ws_s = isWhitespace() ? "whitespace" : ""; + final String undef_s = isUndefined() ? "undefined" : ""; + contour_s = "non-cont("+ws_s+undef_s+")"; + } else { + contour_s = "contour"; + } + final String name_s = null != name ? name : ""; + final String shape_s = null != shape ? "shape "+shape.getVertexCount()+"v" : "shape null"; + sb.append("Glyph id ").append(id).append(" '").append(name_s).append("', ").append(contour_s) + .append(", shape ").append(shape_s) .append(", advance ").append(getAdvanceFU()) .append(", leftSideBearings ").append(getLeftSideBearingsFU()) .append(", ").append(getBoundsFU()); |