diff options
Diffstat (limited to 'src/jogl/classes/jogamp')
9 files changed, 497 insertions, 259 deletions
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java index 369d0b493..331116f7e 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/CDTriangulator2D.java @@ -80,20 +80,20 @@ public class CDTriangulator2D implements Triangulator { @Override public final void addCurve(final List<Triangle> sink, final Outline polyline, final float sharpness) { - Loop loop = null; - - if(!loops.isEmpty()) { - loop = getContainerLoop(polyline); - } + Loop loop = getContainerLoop(polyline); if(loop == null) { - final GraphOutline outline = new GraphOutline(polyline); + final Winding winding = Winding.CCW; // -> HEdge.BOUNDARY + // Too late: polyline.setWinding(winding); + final GraphOutline outline = new GraphOutline(polyline); // , winding); final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, false, sharpness); // vertices.addAll(polyline.getVertices()); - loop = new Loop(innerPoly, Winding.CCW); + loop = new Loop(innerPoly, winding); loops.add(loop); } else { - final GraphOutline outline = new GraphOutline(polyline); + // final Winding winding = Winding.CW; // -> HEdge.HOLE + // Not required, handled in Loop.initFromPolyline(): polyline.setWinding(winding); + final GraphOutline outline = new GraphOutline(polyline); // , winding); final GraphOutline innerPoly = extractBoundaryTriangles(sink, outline, true, sharpness); // vertices.addAll(innerPoly.getVertices()); loop.addConstraintCurve(innerPoly); @@ -221,12 +221,15 @@ public class CDTriangulator2D implements Triangulator { } private Loop getContainerLoop(final Outline polyline) { - final ArrayList<Vertex> vertices = polyline.getVertices(); - for(int i=0; i < loops.size(); i++) { - final Loop loop = loops.get(i); - for(int j=0; j < vertices.size(); j++) { - if( loop.checkInside( vertices.get(j) ) ) { - return loop; + final int count = loops.size(); + if( 0 < count ) { + final ArrayList<Vertex> vertices = polyline.getVertices(); + for(int i=0; i < count; i++) { + final Loop loop = loops.get(i); + for(int j=0; j < vertices.size(); j++) { + if( loop.checkInside( vertices.get(j) ) ) { + return loop; + } } } } diff --git a/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java b/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java index 81e6efdad..75192d45a 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import com.jogamp.graph.geom.Outline; import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.plane.Winding; public class GraphOutline { final private Outline outline; @@ -40,11 +41,14 @@ public class GraphOutline { this.outline = new Outline(); } - /**Create a control polyline of control vertices + /** + * Create a control polyline of control vertices * the curve pieces can be identified by onCurve flag * of each cp the control polyline is open by default + * + * @param ol the source {@link Outline} */ - public GraphOutline(final Outline ol){ + public GraphOutline(final Outline ol) { this.outline = ol; final ArrayList<Vertex> vertices = this.outline.getVertices(); for(int i = 0; i< vertices.size(); i++){ diff --git a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java index 5d1bc051f..1d8264607 100644 --- a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java +++ b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java @@ -34,6 +34,7 @@ import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.geom.plane.Winding; import com.jogamp.graph.geom.Triangle; import com.jogamp.opengl.math.VectorUtil; +import com.jogamp.opengl.math.Vert2fImmutable; import com.jogamp.opengl.math.geom.AABBox; public class Loop { @@ -91,9 +92,24 @@ public class Loop { return (root.getNext().getNext().getNext() == root); } - /**Create a connected list of half edges (loop) + private static float area(final ArrayList<GraphVertex> vertices) { + final int n = vertices.size(); + float area = 0.0f; + for (int p = n - 1, q = 0; q < n; p = q++) { + final float[] pCoord = vertices.get(p).getCoord(); + final float[] qCoord = vertices.get(q).getCoord(); + area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1]; + } + return area; + } + private static Winding getWinding(final ArrayList<GraphVertex> vertices) { + return area(vertices) >= 0 ? Winding.CCW : Winding.CW ; + } + + /** + * Create a connected list of half edges (loop) * from the boundary profile - * @param reqWinding requested winding of edges (CCW or CW) + * @param reqWinding requested winding of edges, either {@link Winding#CCW} for {@link HEdge#BOUNDARY} or {@link Winding#CW} for {@link HEdge#HOLE} */ private HEdge initFromPolyline(final GraphOutline outline, final Winding reqWinding){ final ArrayList<GraphVertex> vertices = outline.getGraphPoint(); @@ -101,57 +117,64 @@ public class Loop { if(vertices.size()<3) { throw new IllegalArgumentException("outline's vertices < 3: " + vertices.size()); } - final Winding hasWinding = VectorUtil.getWinding( - vertices.get(0).getPoint(), - vertices.get(1).getPoint(), - vertices.get(2).getPoint()); - //FIXME: handle case when vertices come inverted - Rami - // skips inversion CW -> CCW - final boolean invert = hasWinding != reqWinding && - reqWinding == Winding.CW; - - final int max; + final Winding hasWinding = getWinding( vertices ); // requires area-winding detection + final int edgeType = reqWinding == Winding.CCW ? HEdge.BOUNDARY : HEdge.HOLE ; - int index; HEdge firstEdge = null; HEdge lastEdge = null; - if(!invert) { - max = vertices.size(); - index = 0; - } else { - max = -1; - index = vertices.size() -1; - } - - while(index != max){ - final GraphVertex v1 = vertices.get(index); - box.resize(v1.getX(), v1.getY(), v1.getZ()); - - final HEdge edge = new HEdge(v1, edgeType); - - v1.addEdge(edge); - if(lastEdge != null) { - lastEdge.setNext(edge); - edge.setPrev(lastEdge); - } else { - firstEdge = edge; - } - - if(!invert) { - if(index == vertices.size()-1) { + /** + * The winding conversion CW -> CCW can't be resolved here (-> Rami?) + * Therefore we require outline boundaries to be in CCW, see API-doc comment in OutlineShape. + * + * Original comment: + * FIXME: handle case when vertices come inverted - Rami + * Skips inversion CW -> CCW + */ + if( hasWinding == reqWinding || reqWinding == Winding.CCW ) { + // Correct Winding or skipped CW -> CCW (no inversion possible here, too late ??) + final int max = vertices.size() - 1; + for(int index = 0; index <= max; ++index) { + final GraphVertex v1 = vertices.get(index); + box.resize(v1.getX(), v1.getY(), v1.getZ()); + + final HEdge edge = new HEdge(v1, edgeType); + + v1.addEdge(edge); + if(lastEdge != null) { + lastEdge.setNext(edge); + edge.setPrev(lastEdge); + } else { + firstEdge = edge; + } + if(index == max ) { edge.setNext(firstEdge); firstEdge.setPrev(edge); } - index++; - } else { + lastEdge = edge; + } + } else { // if( reqWinding == Winding.CW ) { + // CCW -> CW + for(int index = vertices.size() - 1; index >= 0; --index) { + final GraphVertex v1 = vertices.get(index); + box.resize(v1.getX(), v1.getY(), v1.getZ()); + + final HEdge edge = new HEdge(v1, edgeType); + + v1.addEdge(edge); + if(lastEdge != null) { + lastEdge.setNext(edge); + edge.setPrev(lastEdge); + } else { + firstEdge = edge; + } + if (index == 0) { edge.setNext(firstEdge); firstEdge.setPrev(edge); } - index--; + lastEdge = edge; } - lastEdge = edge; } return firstEdge; } @@ -159,7 +182,7 @@ public class Loop { public void addConstraintCurve(final GraphOutline polyline) { // GraphOutline outline = new GraphOutline(polyline); /**needed to generate vertex references.*/ - initFromPolyline(polyline, Winding.CW); + initFromPolyline(polyline, Winding.CW); // -> HEdge.HOLE final GraphVertex v3 = locateClosestVertex(polyline); final HEdge v3Edge = v3.findBoundEdge(); diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java index 382d35a73..f5358b74b 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java @@ -1,5 +1,5 @@ /** - * Copyright 2011 JogAmp Community. All rights reserved. + * Copyright 2011-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -56,7 +56,7 @@ class TypecastFont implements Font { /* pp */ final TTFont font; private final CmapFormat cmapFormat; private final int cmapentries; - private final IntObjectHashMap char2Glyph; + private final IntObjectHashMap idToGlyph; private final TypecastHMetrics metrics; // FIXME: Add cache size to limit memory usage ?? @@ -147,7 +147,7 @@ class TypecastFont implements Font { } } } - char2Glyph = new IntObjectHashMap(cmapentries + cmapentries/4); + idToGlyph = new IntObjectHashMap(cmapentries + cmapentries/4); metrics = new TypecastHMetrics(this); } @@ -197,11 +197,9 @@ class TypecastFont implements Font { } @Override - public Glyph getGlyph(final char symbol) { - TypecastGlyph result = (TypecastGlyph) char2Glyph.get(symbol); + public Glyph getGlyph(final int glyph_id) { + TypecastGlyph result = (TypecastGlyph) idToGlyph.get(glyph_id); if (null == result) { - final int glyph_id = getGlyphID( symbol ); - jogamp.graph.font.typecast.ot.Glyph glyph = font.getGlyph(glyph_id); final int glyph_advance; final AABBox glyph_bbox; @@ -222,9 +220,9 @@ class TypecastFont implements Font { break; } if(null == glyph) { - throw new RuntimeException("Could not retrieve glyph for symbol: <"+symbol+"> "+(int)symbol+" -> glyph id "+glyph_id); + throw new RuntimeException("Could not retrieve glyph for glyph id "+glyph_id); } - final OutlineShape shape = TypecastRenderer.buildShape(metrics.getUnitsPerEM(), symbol, glyph, vertexFactory); + final OutlineShape shape = TypecastRenderer.buildShape(metrics.getUnitsPerEM(), glyph, vertexFactory); KernSubtable kernSub = null; { final KernTable kern = font.getKernTable(); @@ -232,17 +230,17 @@ class TypecastFont implements Font { kernSub = kern.getSubtable0(); } } - result = new TypecastGlyph(this, symbol, glyph_id, glyph_bbox, glyph_advance, kernSub, shape); + result = new TypecastGlyph(this, glyph_id, glyph_bbox, glyph_advance, kernSub, shape); if(DEBUG) { final PostTable post = font.getPostTable(); final String glyph_name = null != post ? post.getGlyphName(glyph_id) : "n/a"; - System.err.println("New glyph: " + (int)symbol + " ( " + symbol +" ) -> " + glyph_id + "/'"+glyph_name+"', contours " + glyph.getPointCount() + ": " + shape); + System.err.println("New glyph: " + glyph_id + "/'"+glyph_name+"', contours " + glyph.getPointCount() + ": " + shape); System.err.println(" "+glyph); System.err.println(" "+result); } glyph.clearPointData(); - char2Glyph.put(symbol, result); + idToGlyph.put(glyph_id, result); } return result; } @@ -256,106 +254,154 @@ class TypecastFont implements Font { public int getLineHeightFU() { final Metrics metrics = getMetrics(); final int lineGap = metrics.getLineGapFU() ; // negative value! - final int ascent = metrics.getAscentFU() ; // negative value! final int descent = metrics.getDescentFU() ; // positive value! + final int ascent = metrics.getAscentFU() ; // negative value! final int advanceY = lineGap - descent + ascent; // negative value! return -advanceY; } @Override - public float getMetricWidth(final CharSequence string) { - return metrics.getScale( getMetricWidthFU(string) ); + public AABBox getMetricBounds(final CharSequence string) { + return getMetricBoundsFU(string).scale2(1.0f/metrics.getUnitsPerEM(), new float[3]); } @Override - public int getMetricWidthFU(final CharSequence string) { - int width = 0; - final int len = string.length(); - for (int i=0; i< len; i++) { + public AABBox getMetricBoundsFU(final CharSequence string) { + if (null == string || 0 == string.length() ) { + return new AABBox(); + } + final AABBox res = new AABBox(); + final int charCount = string.length(); + + final int lineHeight = getLineHeightFU(); + + int y = 0; + int advanceTotal = 0; + + for (int i=0; i<charCount; i++) { final char character = string.charAt(i); if (character == '\n') { - width = 0; + advanceTotal = 0; + y -= lineHeight; + } else if (character == ' ') { + advanceTotal += getAdvanceWidthFU(Glyph.ID_SPACE); } else { - final Glyph glyph = getGlyph(character); - width += glyph.getAdvanceFU(); + advanceTotal += getAdvanceWidthFU( getGlyphID( character ) ); } + res.resize(advanceTotal, y, 0f); + } + if( 0 < advanceTotal ) { + // add one line for current non '\n' terminated + y -= lineHeight; + res.resize(advanceTotal, y, 0f); } - return width; + return res; } @Override - public float getMetricHeight(final CharSequence string) { - return metrics.getScale( getMetricHeightFU(string) ); + public AABBox getGlyphBounds(final CharSequence string) { + return getGlyphBoundsFU(string).scale2(1.0f/metrics.getUnitsPerEM(), new float[3]); } @Override - public int getMetricHeightFU(final CharSequence string) { - int height = 0; + public AABBox getGlyphBoundsFU(final CharSequence string) { + if (null == string || 0 == string.length() ) { + return new AABBox(); + } + final AffineTransform temp1 = new AffineTransform(); + final AffineTransform temp2 = new AffineTransform(); + + final AABBox res = new AABBox(); + final int charCount = string.length(); + + final int lineHeight = getLineHeightFU(); - for (int i=0; i<string.length(); i++) { + int y = 0; + int advanceTotal = 0; + Font.Glyph left_glyph = null; + final AABBox temp_box = new AABBox(); + + for(int i=0; i< charCount; i++) { final char character = string.charAt(i); - if (character != ' ') { - final Glyph glyph = getGlyph(character); - height = (int)Math.ceil(Math.max(glyph.getBBoxFU().getHeight(), height)); + if( '\n' == character ) { + y -= lineHeight; + advanceTotal = 0; + left_glyph = null; + } else if (character == ' ') { + advanceTotal += getAdvanceWidthFU(Glyph.ID_SPACE); + left_glyph = null; + } else { + // reset transform + temp1.setToIdentity(); + final int glyph_id = getGlyphID(character); + final Font.Glyph glyph = getGlyph(glyph_id); + final OutlineShape glyphShape = glyph.getShape(); + if( null == glyphShape ) { + left_glyph = null; + continue; + } + if( null != left_glyph ) { + advanceTotal += left_glyph.getKerningFU(glyph_id); + } + temp1.translate(advanceTotal, y, temp2); + res.resize(temp1.transform(glyph.getBBoxFU(), temp_box)); + advanceTotal += glyph.getAdvanceFU(); + left_glyph = glyph; } } - return height; + return res; } @Override - public AABBox getMetricBounds(final CharSequence string) { - return getMetricBoundsFU(string).scale2(1.0f/metrics.getUnitsPerEM(), new float[3]); + public AABBox getGlyphShapeBounds(final CharSequence string) { + return getGlyphShapeBounds(null, string); } - @Override - public AABBox getMetricBoundsFU(final CharSequence string) { - if (string == null) { + public AABBox getGlyphShapeBounds(final AffineTransform transform, final CharSequence string) { + if (null == string || 0 == string.length() ) { return new AABBox(); } - final int charCount = string.length(); - final int lineHeight = getLineHeightFU(); - int totalHeight = 0; - int totalWidth = 0; - int curLineWidth = 0; - for (int i=0; i<charCount; i++) { - final char character = string.charAt(i); - if (character == '\n') { - totalWidth = Math.max(curLineWidth, totalWidth); - curLineWidth = 0; - totalHeight += lineHeight; - continue; - } - curLineWidth += getAdvanceWidthFU( getGlyphID( character ) ); - } - if (curLineWidth > 0) { - totalHeight += lineHeight; - totalWidth = Math.max(curLineWidth, totalWidth); - } - return new AABBox(0, 0, 0, totalWidth, totalHeight,0); + final OutlineShape.Visitor visitor = new OutlineShape.Visitor() { + @Override + public final void visit(final OutlineShape shape, final AffineTransform t) { + // nop + } }; + return processString(visitor, transform, string); + } + + @Override + public AABBox processString(final OutlineShape.Visitor visitor, final AffineTransform transform, + final CharSequence string) { + return processString(visitor, transform, string, new AffineTransform(), new AffineTransform()); } @Override - public AABBox getPointsBoundsFU(final AffineTransform transform, final CharSequence string) { - if (string == null) { + public AABBox processString(final OutlineShape.Visitor visitor, final AffineTransform transform, + final CharSequence string, + final AffineTransform temp1, final AffineTransform temp2) { + if (null == string || 0 == string.length() ) { return new AABBox(); } - final AffineTransform temp1 = new AffineTransform(); - final AffineTransform temp2 = new AffineTransform(); - final int charCount = string.length(); - final int lineHeight = getLineHeightFU(); - final AABBox tbox = new AABBox(); final AABBox res = new AABBox(); + final int charCount = string.length(); + + // region.setFlipped(true); + final float lineHeight = getLineHeight(); float y = 0; float advanceTotal = 0; + Font.Glyph left_glyph = null; + final AABBox temp_box = new AABBox(); for(int i=0; i< charCount; i++) { final char character = string.charAt(i); if( '\n' == character ) { y -= lineHeight; advanceTotal = 0; + left_glyph = null; } else if (character == ' ') { - advanceTotal += getAdvanceWidthFU(Glyph.ID_SPACE); + advanceTotal += getAdvanceWidth(Glyph.ID_SPACE); + left_glyph = null; } else { // reset transform if( null != transform ) { @@ -363,28 +409,28 @@ class TypecastFont implements Font { } else { temp1.setToIdentity(); } - temp1.translate(advanceTotal, y, temp2); - tbox.reset(); - - final Font.Glyph glyph = getGlyph(character); - res.resize(temp1.transform(glyph.getBBoxFU(), tbox)); - + final int glyph_id = getGlyphID(character); + final Font.Glyph glyph = getGlyph(glyph_id); final OutlineShape glyphShape = glyph.getShape(); if( null == glyphShape ) { + left_glyph = null; continue; } - advanceTotal += glyph.getAdvanceFU(); + 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(glyphShape, temp1); + advanceTotal += glyph.getAdvance(); + left_glyph = glyph; } } return res; } @Override - public AABBox getPointsBounds(final AffineTransform transform, final CharSequence string) { - return getPointsBoundsFU(transform, string).scale2(1.0f/metrics.getUnitsPerEM(), new float[3]); - } - - @Override final public int getNumGlyphs() { return font.getNumGlyphs(); } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java index e6a655661..12d492f6e 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java @@ -1,5 +1,5 @@ /** - * Copyright 2011 JogAmp Community. All rights reserved. + * Copyright 2011-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -65,7 +65,7 @@ public final class TypecastGlyph implements Font.Glyph { /** in font-units */ public final AABBox getBBoxFU() { return this.bbox; } - /** Return advance in font units to be divided by unitsPerEM */ + /** Return advance in font units, sourced from `hmtx` table. */ public final int getAdvanceFU() { return this.advance; } @Override @@ -104,7 +104,6 @@ public final class TypecastGlyph implements Font.Glyph { return dst; } - private final char symbol; private final int id; private final int[/*right_glyphid*/][/*value*/] kerning; private final boolean kerning_horizontal; @@ -115,15 +114,13 @@ public final class TypecastGlyph implements Font.Glyph { /** * * @param font - * @param symbol * @param id * @param bbox in font-units * @param advance from hmtx in font-units * @param shape */ - protected TypecastGlyph(final TypecastFont font, final char symbol, final int id, final AABBox bbox, final int advance, + protected TypecastGlyph(final TypecastFont font, final int id, final AABBox bbox, final int advance, final KernSubtable kernSub, final OutlineShape shape) { - this.symbol = symbol; this.id = id; if( null != kernSub && kernSub.areKerningValues() ) { int pair_sz = 64; @@ -160,11 +157,6 @@ public final class TypecastGlyph implements Font.Glyph { return this.metrics.getFont(); } - @Override - public final char getSymbol() { - return this.symbol; - } - public final Metrics getMetrics() { return this.metrics; } @@ -195,6 +187,12 @@ public final class TypecastGlyph implements Font.Glyph { } @Override + public final AABBox getBBox() { + final AABBox dest = new AABBox(); + return dest.copy(metrics.getBBoxFU()).scale2(1.0f/metrics.getUnitsPerEM(), new float[2]); + } + + @Override public final int getAdvanceFU() { return metrics.getAdvanceFU(); } @Override diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java index 274114e4a..cae8b2755 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java @@ -1,5 +1,5 @@ /** - * Copyright 2011 JogAmp Community. All rights reserved. + * Copyright 2011-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java index 60319d842..2a895a2f1 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java @@ -1,5 +1,5 @@ /** - * Copyright 2011 JogAmp Community. All rights reserved. + * Copyright 2011-2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -27,7 +27,9 @@ */ package jogamp.graph.font.typecast; +import jogamp.graph.font.typecast.ot.Glyph; import jogamp.graph.font.typecast.ot.Point; +import jogamp.graph.font.typecast.ot.T2Glyph; import jogamp.opengl.Debug; import com.jogamp.graph.curve.OutlineShape; @@ -46,50 +48,76 @@ import com.jogamp.graph.geom.Vertex.Factory; */ public class TypecastRenderer { private static final boolean DEBUG = Debug.debug("graph.font.Renderer"); + private static final boolean PRINT_CODE = Debug.debug("graph.font.Renderer.Code"); private static void addShapeMoveTo(final float unitsPerEM, final OutlineShape shape, final Point p1) { - if( DEBUG ) { System.err.println("Shape.MoveTo: "+p1); } + if( PRINT_CODE ) { + System.err.println("// Shape.MoveTo:"); + System.err.printf("shape.closeLastOutline(false);%n"); + System.err.printf("shape.addEmptyOutline();%n"); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p1.x/unitsPerEM, p1.y/unitsPerEM, true); + } shape.closeLastOutline(false); shape.addEmptyOutline(); - shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, p1.onCurve); + shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, true); } private static void addShapeLineTo(final float unitsPerEM, final OutlineShape shape, final Point p1) { - if( DEBUG ) { System.err.println("Shape.LineTo: "+p1); } - shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, p1.onCurve); + if( PRINT_CODE ) { + System.err.println("// Shape.LineTo:"); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p1.x/unitsPerEM, p1.y/unitsPerEM, true); + } + shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, true); } private static void addShapeQuadTo(final float unitsPerEM, final OutlineShape shape, final Point p1, final Point p2) { - if( DEBUG ) { System.err.println("Shape.QuadTo: "+p1+", "+p2); } - shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, p1.onCurve); - shape.addVertex(0, p2.x/unitsPerEM, p2.y/unitsPerEM, p2.onCurve); + if( PRINT_CODE ) { + System.err.println("// Shape.QuadTo:"); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p1.x/unitsPerEM, p1.y/unitsPerEM, false); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p2.x/unitsPerEM, p2.y/unitsPerEM, true); + } + shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, false); + shape.addVertex(0, p2.x/unitsPerEM, p2.y/unitsPerEM, true); + } + private static void addShapeQuadTo(final float unitsPerEM, final OutlineShape shape, final Point p1, final float p2x, final float p2y) { + if( PRINT_CODE ) { + System.err.println("// Shape.QuadTo:"); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p1.x/unitsPerEM, p1.y/unitsPerEM, false); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p2x/unitsPerEM, p2y/unitsPerEM, true); + } + shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, false); + shape.addVertex(0, p2x/unitsPerEM, p2y/unitsPerEM, true); } - private static void addShapeQuadTo(final float unitsPerEM, final OutlineShape shape, final Point p1, - final float p2x, final float p2y, final boolean p2OnCurve) { - if( DEBUG ) { System.err.println("Shape.QuadTo: "+p1+", p2 "+p2x+", "+p2y+", onCurve "+p2OnCurve); } - shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, p1.onCurve); - shape.addVertex(0, p2x/unitsPerEM, p2y/unitsPerEM, p2OnCurve); + private static void addShapeCubicTo(final float unitsPerEM, final OutlineShape shape, final Point p1, final Point p2, final Point p3) { + if( PRINT_CODE ) { + System.err.println("// Shape.CubicTo:"); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p1.x/unitsPerEM, p1.y/unitsPerEM, false); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p2.x/unitsPerEM, p2.y/unitsPerEM, false); + System.err.printf("shape.addVertex(%d, %ff, %ff, %b);%n", 0, p3.x/unitsPerEM, p3.y/unitsPerEM, true); + } + shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, false); + shape.addVertex(0, p2.x/unitsPerEM, p2.y/unitsPerEM, false); + shape.addVertex(0, p3.x/unitsPerEM, p3.y/unitsPerEM, true); } - /** - private static void addShapeCubicTo(final float unitsPerEM, final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, Point p2, Point p3) { - shape.addVertex(0, p1.x/unitsPerEM, p1.y/unitsPerEM, p1.onCurve); - shape.addVertex(0, p2.x/unitsPerEM, p2.y/unitsPerEM, p2.onCurve); - shape.addVertex(0, p3.x/unitsPerEM, p3.y/unitsPerEM, p3.onCurve); - } */ - public static OutlineShape buildShape(final int unitsPerEM, final char symbol, final jogamp.graph.font.typecast.ot.Glyph glyph, final Factory<? extends Vertex> vertexFactory) { - // - // See Typecast: GlyphPathFactory.addContourToPath(..) - // + public static OutlineShape buildShape(final int unitsPerEM, final Glyph glyph, final Factory<? extends Vertex> vertexFactory) { if (glyph == null) { return null; } - final OutlineShape shape = new OutlineShape(vertexFactory); - buildShapeImpl(unitsPerEM, shape, symbol, glyph); - shape.setIsQuadraticNurbs(); + if (glyph instanceof T2Glyph) { + // Type 1/2: Cubic + if( PRINT_CODE ) { System.err.printf("%n// Start Type-2 Shape for Glyph %d%n", glyph.getID()); } + buildShapeType2(unitsPerEM, shape, (T2Glyph)glyph); + } else { + // TTF: quadratic only + if( PRINT_CODE ) { System.err.printf("%n// Start TTF Shape for Glyph %d%n", glyph.getID()); } + buildShapeTTF(unitsPerEM, shape, glyph); + shape.setIsQuadraticNurbs(); + } + if( PRINT_CODE ) { System.err.printf("// End Shape for Glyph %d%n%n", glyph.getID()); } return shape; } - private static void buildShapeImpl(final float unitsPerEM, final OutlineShape shape, final char symbol, final jogamp.graph.font.typecast.ot.Glyph glyph) { + private static void buildShapeTTF(final float unitsPerEM, final OutlineShape shape, final Glyph glyph) { // Iterate through all of the points in the glyph. Each time we find a // contour end point, add the point range to the path. int startIndex = 0; @@ -99,98 +127,125 @@ public class TypecastRenderer { count++; if ( glyph.getPoint(i).endOfContour ) { int offset = 0; - while ( offset < count - 1 ) { // require at least +1 point (last one is end-of-contour) - final Point p0 = glyph.getPoint(startIndex + offset%count); - final Point p1 = glyph.getPoint(startIndex + (offset+1)%count); - final Point p2 = glyph.getPoint(startIndex + (offset+2)%count); - final Point p3 = offset+3 < count ? glyph.getPoint(startIndex + offset+3) : null; + while ( offset < count ) { + final int point_0_idx = startIndex + offset%count; + final Point point_m = glyph.getPoint((offset==0) ? startIndex+count-1 : startIndex+(offset-1)%count); + final Point point_0 = glyph.getPoint(point_0_idx); + final Point point_1 = glyph.getPoint(startIndex + (offset+1)%count); + final Point point_2 = glyph.getPoint(startIndex + (offset+2)%count); + // final Point point_3 = offset+3 < count ? glyph.getPoint(startIndex + offset+3) : null; if( DEBUG ) { - System.err.println("GlyphShape<"+symbol+">: offset "+offset+" of "+count+"/"+totalPoints+" points"); - final int pMIdx= (offset==0) ? startIndex+count-1 : startIndex+(offset-1)%count; - final Point pM = glyph.getPoint(pMIdx); - final int p0Idx = startIndex + offset%count; - final int p1Idx = startIndex + (offset+1)%count; - final int p2Idx = startIndex + (offset+2)%count; - final int p3Idx = startIndex + (offset+3)%count; - System.err.println("\t pM["+pMIdx+"] "+pM); - System.err.println("\t p0["+p0Idx+"] "+p0); - System.err.println("\t p1["+p1Idx+"] "+p1); - System.err.println("\t p2["+p2Idx+"] "+p2); - System.err.println("\t p3["+p3Idx+"] "+p3); + System.err.println("GlyphShape<"+glyph.getID()+">: offset "+offset+" of "+count+"/"+totalPoints+" points"); + final int point_m_idx= (offset==0) ? startIndex+count-1 : startIndex+(offset-1)%count; + final int point_1_idx = startIndex + (offset+1)%count; + final int point_2_idx = startIndex + (offset+2)%count; + // final int point_3_idx = startIndex + (offset+3)%count; + System.err.println("\t pM["+point_m_idx+"] "+point_m); + System.err.println("\t p0["+point_0_idx+"] "+point_0); + System.err.println("\t p1["+point_1_idx+"] "+point_1); + System.err.println("\t p2["+point_2_idx+"] "+point_2); + // System.err.println("\t p3["+point_3_idx+"] "+point_3); } if(offset == 0) { - addShapeMoveTo(unitsPerEM, shape, p0); - // gp.moveTo(point.x, point.y); + addShapeMoveTo(unitsPerEM, shape, point_0); // OK } - - if( p0.endOfContour ) { - // Branch-0: EOC ** SHALL NEVER HAPPEN ** - if( DEBUG ) { System.err.println("B0 .. end-of-contour **** EOC"); } - shape.closeLastOutline(false); - break; - } else if (p0.onCurve) { - if (p1.onCurve) { + if (point_0.onCurve) { + if (point_1.onCurve) { // Branch-1: point.onCurve && p1.onCurve - if( DEBUG ) { System.err.println("B1 .. line-to p0-p1"); } - - // s = new Line2D.Float(point.x, point.y, p1.x, p1.y); - // gp.lineTo( p1.x, p1.y ); - addShapeLineTo(unitsPerEM, shape, p1); + if( PRINT_CODE ) { System.err.printf("// %03d: B1: line-to p0-p1%n", point_0_idx); } + addShapeLineTo(unitsPerEM, shape, point_1); // OK offset++; } else { - if (p2.onCurve) { + if (point_2.onCurve) { // Branch-2: point.onCurve && !p1.onCurve && p2.onCurve - if( DEBUG ) { System.err.println("B2 .. quad-to p0-p1-p2"); } - - // s = new QuadCurve2D.Float( point.x, point.y, p1.x, p1.y, p2.x, p2.y); - // gp.quadTo(p1.x, p1.y, p2.x, p2.y); - addShapeQuadTo(unitsPerEM, shape, p1, p2); + if( PRINT_CODE ) { System.err.printf("// %03d: B2: quad-to p0-p1-p2%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_1, point_2); // OK offset+=2; } else { - if (null != p3 && p3.onCurve) { + /** if (null != point_3 && point_3.onCurve) { + // Not required, handled via B4 and subsequent B6! // Branch-3: point.onCurve && !p1.onCurve && !p2.onCurve && p3.onCurve - if( DEBUG ) { System.err.println("B3 .. 2-quad p0-p1-p1_2, p1_2-p2-p3 **** 2QUAD"); } - // addShapeCubicTo(shape, vertexFactory, p1, p2, p3); - addShapeQuadTo(unitsPerEM, shape, p1, midValue(p1.x, p2.x), - midValue(p1.y, p2.y), - true); - addShapeQuadTo(unitsPerEM, shape, p2, p3); + if( PRINT_CODE ) { System.err.printf("// %03d: B3: p0-p1-p1_2, p1_2-p2-p3 **** 2QUAD%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_1, midValue(point_1.x, point_2.x), + midValue(point_1.y, point_2.y)); + addShapeQuadTo(unitsPerEM, shape, point_2, point_3); offset+=3; - } else { + } else */ { // Branch-4: point.onCurve && !p1.onCurve && !p2.onCurve && !p3.onCurve - if( DEBUG ) { System.err.println("B4 .. quad-to p0-p1-p2h **** MID"); } - - // s = new QuadCurve2D.Float(point.x,point.y,p1.x,p1.y, - // midValue(p1.x, p2.x), midValue(p1.y, p2.y)); - // gp.quadTo(p1.x, p1.y, midValue(p1.x, p2.x), midValue(p1.y, p2.y)); - addShapeQuadTo(unitsPerEM, shape, p1, midValue(p1.x, p2.x), - midValue(p1.y, p2.y), - true); + if( PRINT_CODE ) { System.err.printf("// %03d: B4: quad-to p0-p1-p2h **** MID%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_1, midValue(point_1.x, point_2.x), + midValue(point_1.y, point_2.y)); offset+=2; // Skip p2 as done in Typecast } } } } else { - if (!p1.onCurve) { + if (!point_1.onCurve) { // Branch-5: !point.onCurve && !p1.onCurve - if( DEBUG ) { System.err.println("B5 .. quad-to pMh-p0-p1h ***** MID"); } - // s = new QuadCurve2D.Float(midValue(pM.x, point.x), midValue(pM.y, point.y), - // point.x, point.y, - // midValue(point.x, p1.x), midValue(point.y, p1.y)); - addShapeQuadTo(unitsPerEM, shape, p0, midValue(p0.x, p1.x), - midValue(p0.y, p1.y), true); + if( PRINT_CODE ) { System.err.printf("// %03d: B5: quad-to pMh-p0-p1h ***** MID%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_0, midValue(point_0.x, point_1.x), // OK + midValue(point_0.y, point_1.y) ); offset++; } else { // Branch-6: !point.onCurve && p1.onCurve - if( DEBUG ) { System.err.println("B6 .. quad-to pMh-p0-p1"); } - // s = new QuadCurve2D.Float(midValue(pM.x, point.x), midValue(pM.y, point.y), - // point.x, point.y, p1.x, p1.y); - // gp.quadTo(point.x, point.y, p1.x, p1.y); - addShapeQuadTo(unitsPerEM, shape, p0, p1); + if( PRINT_CODE ) { System.err.printf("// %03d: B6: quad-to pMh-p0-p1%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_0, point_1); // OK offset++; } } } + if( PRINT_CODE ) { System.err.printf("shape.closeLastOutline(false);%n%n"); } + shape.closeLastOutline(false); + startIndex = i + 1; + count = 0; + } + } + } + + private static void buildShapeType2(final float unitsPerEM, final OutlineShape shape, final T2Glyph glyph) { + // Iterate through all of the points in the glyph. Each time we find a + // contour end point, add the point range to the path. + int startIndex = 0; + int count = 0; + final int totalPoints = glyph.getPointCount(); + for (int i = 0; i < totalPoints; i++) { + count++; + if ( glyph.getPoint(i).endOfContour ) { + int offset = 0; + while ( offset < count ) { + final int point_0_idx = startIndex + offset%count; + final Point point_0 = glyph.getPoint(point_0_idx); + final Point point_1 = glyph.getPoint(startIndex + (offset+1)%count); + final Point point_2 = glyph.getPoint(startIndex + (offset+2)%count); + final Point point_3 = glyph.getPoint(startIndex + (offset+3)%count); + if( DEBUG ) { + System.err.println("GlyphShape<"+glyph.getID()+">: offset "+offset+" of "+count+"/"+totalPoints+" points"); + final int point_1_idx = startIndex + (offset+1)%count; + final int point_2_idx = startIndex + (offset+2)%count; + final int point_3_idx = startIndex + (offset+3)%count; + System.err.println("\t p0["+point_0_idx+"] "+point_0); + System.err.println("\t p1["+point_1_idx+"] "+point_1); + System.err.println("\t p2["+point_2_idx+"] "+point_2); + System.err.println("\t p3["+point_3_idx+"] "+point_3); + } + if(offset == 0) { + addShapeMoveTo(unitsPerEM, shape, point_0); // OK + } + if (point_0.onCurve && point_1.onCurve) { + // Branch-1: point.onCurve && p1.onCurve + if( PRINT_CODE ) { System.err.printf("// %03d: C1: line-to p0-p1%n", point_0_idx); } + addShapeLineTo(unitsPerEM, shape, point_1); // OK + offset++; + } else if (point_0.onCurve && !point_1.onCurve && !point_2.onCurve && point_3.onCurve) { + if( PRINT_CODE ) { System.err.printf("// %03d: C2: cubic-to p0-p1-p2%n", point_0_idx); } + addShapeCubicTo(unitsPerEM, shape, point_0, point_2, point_3); + offset+=3; + } else { + System.out.println("addContourToPath case not catered for!!"); + break; + } + } + if( PRINT_CODE ) { System.err.printf("shape.closeLastOutline(false);%n%n"); } shape.closeLastOutline(false); startIndex = i + 1; count = 0; @@ -198,7 +253,103 @@ public class TypecastRenderer { } } - private static float midValue(final float a, final float b) { - return a + (b - a)/2f; + /** + * Returns the mid-value of two. + * <p> + * Intentionally using integer arithmetic on unitPerEM sized values w/o rounding. + * </p> + */ + private static int midValue(final int a, final int b) { + return a + (b - a)/2; + } + + // + // Leaving Typecast's orig rendering loop in here, transformed to using our OutlineShape. + // This is now actually the same since ours has been re-aligned on 2023-02-15. + // + + @SuppressWarnings("unused") + private static void buildShapeImplX(final float unitsPerEM, final OutlineShape shape, final Glyph glyph) { + // Iterate through all of the points in the glyph. Each time we find a + // contour end point, add the point range to the path. + int firstIndex = 0; + int count = 0; + final int totalPoints = glyph.getPointCount(); + if (glyph instanceof T2Glyph) { + // addContourToPath(unitsPerEM, shape, (T2Glyph) glyph, firstIndex, count); + throw new RuntimeException("T2Glyph Not Yet Supported: "+glyph); + } + if( PRINT_CODE ) { System.err.printf("%n// Start Shape for Glyph %d%n", glyph.getID()); } + for (int i = 0; i < totalPoints; i++) { + count++; + if ( glyph.getPoint(i).endOfContour ) { + addContourToPathX1(unitsPerEM, shape, glyph, firstIndex, count); + firstIndex = i + 1; + count = 0; + } + } + if( PRINT_CODE ) { System.err.printf("// End Shape for Glyph %d%n%n", glyph.getID()); } + } + private static void addContourToPathX1(final float unitsPerEM, final OutlineShape shape, final Glyph glyph, final int startIndex, final int count) { + int offset = 0; + while ( offset < count ) { + final int point_0_idx = startIndex + offset%count; + final Point point_m = glyph.getPoint((offset==0) ? startIndex+count-1 : startIndex+(offset-1)%count); + final Point point_0 = glyph.getPoint(point_0_idx); + final Point point_1 = glyph.getPoint(startIndex + (offset+1)%count); + final Point point_2 = glyph.getPoint(startIndex + (offset+2)%count); + // final Point point_3 = offset+3 < count ? glyph.getPoint(startIndex + offset+3) : null; + if( DEBUG ) { + System.err.println("GlyphShape<"+glyph.getID()+">: offset "+offset+" of "+count+" points"); + final int point_m_idx= (offset==0) ? startIndex+count-1 : startIndex+(offset-1)%count; + final int point_1_idx = startIndex + (offset+1)%count; + final int point_2_idx = startIndex + (offset+2)%count; + // final int p3Idx = startIndex + (offset+3)%count; + System.err.println("\t pM["+point_m_idx+"] "+point_m); + System.err.println("\t p0["+point_0_idx+"] "+point_0); + System.err.println("\t p1["+point_1_idx+"] "+point_1); + System.err.println("\t p2["+point_2_idx+"] "+point_2); + // System.err.println("\t p3["+p3Idx+"] "+point_3); + } + if(offset == 0) { + addShapeMoveTo(unitsPerEM, shape, point_0); + } + if (point_0.onCurve && point_1.onCurve) { + // Branch-1: point.onCurve && p1.onCurve + if( PRINT_CODE ) { System.err.printf("// %03d: B1: line-to p0-p1%n", point_0_idx); } + addShapeLineTo(unitsPerEM, shape, point_1); + offset++; + } else if (point_0.onCurve && !point_1.onCurve && point_2.onCurve) { + // Branch-2: point.onCurve && !p1.onCurve && p2.onCurve + if( PRINT_CODE ) { System.err.printf("// %03d: B2: quad-to p0-p1-p2%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_1, point_2); + offset+=2; + } else if (point_0.onCurve && !point_1.onCurve && !point_2.onCurve) { + // Branch-4: point.onCurve && !p1.onCurve && !p2.onCurve && !p3.onCurve + if( PRINT_CODE ) { System.err.printf("// %03d: B4: quad-to p0-p1-p2h **** MID%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_1, + midValue(point_1.x, point_2.x), + midValue(point_1.y, point_2.y)); + + offset+=2; + } else if (!point_0.onCurve && !point_1.onCurve) { + // Branch-5: !point.onCurve && !p1.onCurve + if( PRINT_CODE ) { System.err.printf("// %03d: B5: quad-to pMh-p0-p1h ***** MID%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_0, + midValue(point_0.x, point_1.x), + midValue(point_0.y, point_1.y) ); + offset++; + } else if (!point_0.onCurve && point_1.onCurve) { + // Branch-6: !point.onCurve && p1.onCurve + if( PRINT_CODE ) { System.err.printf("// %03d: B6: quad-to pMh-p0-p1%n", point_0_idx); } + addShapeQuadTo(unitsPerEM, shape, point_0, point_1); + offset++; + } else { + System.out.println("addContourToPath case not catered for!!"); + break; + } + } + if( PRINT_CODE ) { System.err.printf("shape.closeLastOutline(false);%n%n"); } + shape.closeLastOutline(false); } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/Glyph.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/Glyph.java index 7b29a6c48..5bb610a1c 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/ot/Glyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/Glyph.java @@ -31,25 +31,31 @@ public abstract class Glyph { public Glyph(final int glyph_id) { _glyph_id = glyph_id; } - + /** Return the assigned glyph ID of this instance */ - public final int getGlyphIndex() { return _glyph_id; } - + public final int getID() { return _glyph_id; } + public abstract void clearPointData(); - /** Return the AABBox in font-units */ + /** + * Return the AABBox in font-units. + * <p> + * This is either the GlyphDescripton's min- and maximum for TTF + * or the calculated box over all points. + * </p> + */ public final AABBox getBBox() { return _bbox; } - + /** hmtx value */ public abstract int getAdvanceWidth(); - + /** hmtx value */ public abstract short getLeftSideBearing(); public abstract Point getPoint(int i); public abstract int getPointCount(); - + @Override public abstract String toString(); } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfDescript.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfDescript.java index 2a8deaeeb..45d06e8cb 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfDescript.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfDescript.java @@ -67,19 +67,20 @@ public abstract class GlyfDescript extends Program implements GlyphDescription { static final byte yDual = 0x20; final GlyfTable _parentTable; - private int _glyphIndex; + private final int _glyphIndex; private final int _numberOfContours; - private short _xMin; - private short _yMin; - private short _xMax; - private short _yMax; + private final short _xMin; + private final short _yMin; + private final short _xMax; + private final short _yMax; GlyfDescript( - GlyfTable parentTable, - int glyphIndex, - short numberOfContours, - DataInput di) throws IOException { + final GlyfTable parentTable, + final int glyphIndex, + final short numberOfContours, + final DataInput di) throws IOException { _parentTable = parentTable; + _glyphIndex = glyphIndex; _numberOfContours = numberOfContours; _xMin = di.readShort(); _yMin = di.readShort(); @@ -91,26 +92,32 @@ public abstract class GlyfDescript extends Program implements GlyphDescription { return _numberOfContours; } + @Override public int getGlyphIndex() { return _glyphIndex; } + @Override public short getXMaximum() { return _xMax; } + @Override public short getXMinimum() { return _xMin; } + @Override public short getYMaximum() { return _yMax; } + @Override public short getYMinimum() { return _yMin; } - + + @Override public String toString() { return " numberOfContours: " + _numberOfContours + "\n xMin: " + _xMin + |