diff options
Diffstat (limited to 'src/jogl/classes/jogamp/graph/font')
9 files changed, 248 insertions, 321 deletions
diff --git a/src/jogl/classes/jogamp/graph/font/FontInt.java b/src/jogl/classes/jogamp/graph/font/FontInt.java deleted file mode 100644 index 4366724ad..000000000 --- a/src/jogl/classes/jogamp/graph/font/FontInt.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Copyright 2011 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: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of JogAmp Community. - */ -package jogamp.graph.font; - -import java.util.ArrayList; - -import jogamp.graph.geom.plane.Path2D; - -import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Vertex.Factory; - -public interface FontInt extends Font { - - public interface GlyphInt extends Font.Glyph { - public Path2D getPath(); // unscaled path - public Path2D getPath(float pixelSize); - } - - public ArrayList<OutlineShape> getOutlineShapes(CharSequence string, float pixelSize, Factory<? extends Vertex> vertexFactory); -} diff --git a/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java b/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java index e1e44c92c..c7efe143b 100644 --- a/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java +++ b/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java @@ -38,9 +38,7 @@ import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontSet; import com.jogamp.graph.font.FontFactory; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; import java.net.URLConnection; import java.security.AccessController; import java.security.PrivilegedAction; diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java index 67ae6c387..3cd9ab7c1 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java @@ -27,9 +27,6 @@ */ package jogamp.graph.font.typecast; -import java.util.ArrayList; - -import jogamp.graph.font.FontInt; import jogamp.graph.font.typecast.ot.OTFont; import jogamp.graph.font.typecast.ot.OTFontCollection; import jogamp.graph.font.typecast.ot.table.CmapFormat; @@ -37,32 +34,30 @@ import jogamp.graph.font.typecast.ot.table.CmapIndexEntry; import jogamp.graph.font.typecast.ot.table.CmapTable; import jogamp.graph.font.typecast.ot.table.HdmxTable; import jogamp.graph.font.typecast.ot.table.ID; -import jogamp.graph.geom.plane.AffineTransform; -import jogamp.graph.geom.plane.Path2D; import com.jogamp.common.util.IntObjectHashMap; import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.font.Font; import com.jogamp.graph.font.FontFactory; -import com.jogamp.graph.font.Font.Glyph; +import com.jogamp.graph.geom.SVertex; import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.Vertex.Factory; import com.jogamp.opengl.math.geom.AABBox; -class TypecastFont implements FontInt { +class TypecastFont implements Font { static final boolean DEBUG = false; + private static final Vertex.Factory<SVertex> vertexFactory = SVertex.factory(); - final OTFontCollection fontset; - final OTFont font; - TypecastHMetrics metrics; - final CmapFormat cmapFormat; - int cmapentries; - + // private final OTFontCollection fontset; + /* pp */ final OTFont font; + private final CmapFormat cmapFormat; + private final int cmapentries; + private final IntObjectHashMap char2Glyph; + private final TypecastHMetrics metrics; + private final float[] tmpV3 = new float[3]; // FIXME: Add cache size to limit memory usage ?? - IntObjectHashMap char2Glyph; - public TypecastFont(OTFontCollection fontset) { - this.fontset = fontset; + public TypecastFont(final OTFontCollection fontset) { + // this.fontset = fontset; this.font = fontset.getFont(0); // FIXME: Generic attempt to find the best CmapTable, @@ -124,10 +119,13 @@ class TypecastFont implements FontInt { } } - cmapentries = 0; - for (int i = 0; i < cmapFormat.getRangeCount(); ++i) { - CmapFormat.Range range = cmapFormat.getRange(i); - cmapentries += range.getEndCode() - range.getStartCode() + 1; // end included + { + int _cmapentries = 0; + for (int i = 0; i < cmapFormat.getRangeCount(); ++i) { + CmapFormat.Range range = cmapFormat.getRange(i); + _cmapentries += range.getEndCode() - range.getStartCode() + 1; // end included + } + cmapentries = _cmapentries; } if(DEBUG) { System.err.println("font direction hint: "+font.getHeadTable().getFontDirectionHint()); @@ -140,12 +138,13 @@ class TypecastFont implements FontInt { for (int j = range.getStartCode(); j <= range.getEndCode(); ++j) { final int code = cmapFormat.mapCharCode(j); if(code < 15) { - System.err.println(" char: " + (int)j + " ( " + (char)j +" ) -> " + code); + System.err.println(" char: " + j + " ( " + (char)j +" ) -> " + code); } } } } char2Glyph = new IntObjectHashMap(cmapentries + cmapentries/4); + metrics = new TypecastHMetrics(this); } @Override @@ -168,15 +167,12 @@ class TypecastFont implements FontInt { } @Override - public float getAdvanceWidth(int i, float pixelSize) { - return font.getHmtxTable().getAdvanceWidth(i) * metrics.getScale(pixelSize); + public float getAdvanceWidth(int glyphID, float pixelSize) { + return font.getHmtxTable().getAdvanceWidth(glyphID) * metrics.getScale(pixelSize); } @Override - public Metrics getMetrics() { - if (metrics == null) { - metrics = new TypecastHMetrics(this); - } + public final Metrics getMetrics() { return metrics; } @@ -202,10 +198,10 @@ class TypecastFont implements FontInt { if(null == glyph) { throw new RuntimeException("Could not retrieve glyph for symbol: <"+symbol+"> "+(int)symbol+" -> glyph id "+code); } - Path2D path = TypecastRenderer.buildPath(glyph); - result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), path); + final OutlineShape shape = TypecastRenderer.buildShape(symbol, glyph, vertexFactory); + result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), shape); if(DEBUG) { - System.err.println("New glyph: " + (int)symbol + " ( " + (char)symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + path); + System.err.println("New glyph: " + (int)symbol + " ( " + symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + shape); } final HdmxTable hdmx = font.getHdmxTable(); if (null!= result && null != hdmx) { @@ -227,18 +223,26 @@ class TypecastFont implements FontInt { } @Override - public ArrayList<OutlineShape> getOutlineShapes(CharSequence string, float pixelSize, Factory<? extends Vertex> vertexFactory) { - AffineTransform transform = new AffineTransform(vertexFactory); - return TypecastRenderer.getOutlineShapes(this, string, pixelSize, transform, vertexFactory); + public final float getPixelSize(float fontSize /* points per inch */, float resolution) { + return fontSize * resolution / ( 72 /* points per inch */ ); + } + + @Override + public float getLineHeight(float pixelSize) { + final Metrics metrics = getMetrics(); + final float lineGap = metrics.getLineGap(pixelSize) ; // negative value! + final float ascent = metrics.getAscent(pixelSize) ; // negative value! + final float descent = metrics.getDescent(pixelSize) ; // positive value! + final float advanceY = lineGap - descent + ascent; // negative value! + return -advanceY; } @Override public float getStringWidth(CharSequence string, float pixelSize) { float width = 0; final int len = string.length(); - for (int i=0; i< len; i++) - { - char character = string.charAt(i); + for (int i=0; i< len; i++) { + final char character = string.charAt(i); if (character == '\n') { width = 0; } else { @@ -246,7 +250,6 @@ class TypecastFont implements FontInt { width += glyph.getAdvance(pixelSize, false); } } - return (int)(width + 0.5f); } @@ -254,13 +257,11 @@ class TypecastFont implements FontInt { public float getStringHeight(CharSequence string, float pixelSize) { int height = 0; - for (int i=0; i<string.length(); i++) - { - char character = string.charAt(i); - if (character != ' ') - { - Glyph glyph = getGlyph(character); - AABBox bbox = glyph.getBBox(pixelSize); + for (int i=0; i<string.length(); i++) { + final char character = string.charAt(i); + if (character != ' ') { + final Glyph glyph = getGlyph(character); + AABBox bbox = glyph.getBBox(pixelSize, tmpV3); height = (int)Math.ceil(Math.max(bbox.getHeight(), height)); } } @@ -272,11 +273,8 @@ class TypecastFont implements FontInt { if (string == null) { return new AABBox(); } - final Metrics metrics = getMetrics(); - final float lineGap = metrics.getLineGap(pixelSize); - final float ascent = metrics.getAscent(pixelSize); - final float descent = metrics.getDescent(pixelSize); - final float advanceY = lineGap - descent + ascent; + final float lineHeight = getLineHeight(pixelSize); + float totalHeight = 0; float totalWidth = 0; float curLineWidth = 0; @@ -285,14 +283,14 @@ class TypecastFont implements FontInt { if (character == '\n') { totalWidth = Math.max(curLineWidth, totalWidth); curLineWidth = 0; - totalHeight -= advanceY; + totalHeight += lineHeight; continue; } Glyph glyph = getGlyph(character); curLineWidth += glyph.getAdvance(pixelSize, true); } if (curLineWidth > 0) { - totalHeight -= advanceY; + totalHeight += lineHeight; totalWidth = Math.max(curLineWidth, totalWidth); } return new AABBox(0, 0, 0, totalWidth, totalHeight,0); diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java index 574aeb86d..b0e283278 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java @@ -29,18 +29,15 @@ package jogamp.graph.font.typecast; import java.util.HashMap; -import jogamp.graph.font.FontInt; -import jogamp.graph.geom.plane.AffineTransform; -import jogamp.graph.geom.plane.Path2D; - +import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.font.Font; import com.jogamp.opengl.math.geom.AABBox; -public class TypecastGlyph implements FontInt.GlyphInt { +public class TypecastGlyph implements Font.Glyph { public class Advance { - final Font font; - final float advance; + private final Font font; + private final float advance; HashMap<Float, Float> size2advance = new HashMap<Float, Float>(); public Advance(Font font, float advance) @@ -65,7 +62,7 @@ public class TypecastGlyph implements FontInt.GlyphInt { public float get(float size, boolean useFrationalMetrics) { - Float fo = size2advance.get(size); + final Float fo = size2advance.get(size); if(null == fo) { float value = (this.advance * getScale(size)); if (useFrationalMetrics == false) { @@ -90,8 +87,8 @@ public class TypecastGlyph implements FontInt.GlyphInt { public class Metrics { - AABBox bbox; - Advance advance; + private final AABBox bbox; + private final Advance advance; public Metrics(Font font, AABBox bbox, float advance) { @@ -136,105 +133,86 @@ public class TypecastGlyph implements FontInt.GlyphInt { public static final short MAX_ID = (short)((1 << 16) - 2); private final Font font; + private final char symbol; + private final OutlineShape shape; // in EM units + private final short id; + private final int advance; + private final Metrics metrics; - char symbol; - short id; - int advance; - Metrics metrics; - - protected Path2D path; // in EM units - protected Path2D pathSized; - protected float numberSized; - - protected TypecastGlyph(Font font, char symbol) { - this.font = font; - this.symbol = symbol; - } - - protected TypecastGlyph(Font font, - char symbol, short id, AABBox bbox, int advance, Path2D path) { + protected TypecastGlyph(Font font, char symbol, short id, AABBox bbox, int advance, OutlineShape shape) { this.font = font; this.symbol = symbol; - this.advance = advance; - - init(id, bbox, advance); - - this.path = path; - this.pathSized = null; - this.numberSized = 0.0f; - } - - void init(short id, AABBox bbox, int advance) { + this.shape = shape; this.id = id; this.advance = advance; this.metrics = new Metrics(this.font, bbox, this.advance); } + /** public void reset(Path2D path) { this.path = path; this.metrics.reset(); - } + } */ @Override - public Font getFont() { + public final Font getFont() { return this.font; } @Override - public char getSymbol() { + public final char getSymbol() { return this.symbol; } - AABBox getBBoxUnsized() { + final AABBox getBBoxUnsized() { return this.metrics.getBBox(); } - public AABBox getBBox() { + @Override + public final AABBox getBBox() { return this.metrics.getBBox(); } - public Metrics getMetrics() { + public final Metrics getMetrics() { return this.metrics; } - public short getID() { + @Override + public final short getID() { return this.id; } - public float getScale(float pixelSize) { + @Override + public final float getScale(float pixelSize) { return this.metrics.getScale(pixelSize); } @Override - public AABBox getBBox(float pixelSize) { + public final AABBox getBBox(float pixelSize, float[] tmpV3) { final float size = getScale(pixelSize); AABBox newBox = getBBox().clone(); - newBox.scale(size); + newBox.scale(size, tmpV3); return newBox; } - protected void addAdvance(float advance, float size) { + protected final void addAdvance(float advance, float size) { this.metrics.addAdvance(advance, size); } @Override - public float getAdvance(float pixelSize, boolean useFrationalMetrics) { + public final float getAdvance(float pixelSize, boolean useFrationalMetrics) { return this.metrics.getAdvance(pixelSize, useFrationalMetrics); } @Override - public Path2D getPath() { - return this.path; + public final OutlineShape getShape() { + return this.shape; } @Override - public Path2D getPath(float pixelSize) { - final float size = getScale(pixelSize); - - if (this.numberSized != size) { - this.numberSized = size; - this.pathSized = AffineTransform.getScaleInstance(null, size, size).createTransformedShape(getPath()); - } - return this.pathSized; + public final int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + font.getName(Font.NAME_UNIQUNAME).hashCode(); + return ((hash << 5) - hash) + id; } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java index ecc41e438..4064e6463 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java @@ -50,7 +50,7 @@ class TypecastHMetrics implements Metrics { headTable = this.fontImpl.font.getHeadTable(); hheaTable = this.fontImpl.font.getHheaTable(); // vheaTable = this.fontImpl.font.getVheaTable(); - unitsPerEM_Inv = 1.0f / ( (float) headTable.getUnitsPerEm() ); + unitsPerEM_Inv = 1.0f / ( headTable.getUnitsPerEm() ); int maxWidth = headTable.getXMax() - headTable.getXMin(); int maxHeight = headTable.getYMax() - headTable.getYMin(); @@ -82,9 +82,9 @@ class TypecastHMetrics implements Metrics { return pixelSize * unitsPerEM_Inv; } @Override - public final AABBox getBBox(float pixelSize) { + public final AABBox getBBox(float pixelSize, float[] tmpV3) { AABBox res = new AABBox(bbox.getLow(), bbox.getHigh()); - res.scale(getScale(pixelSize)); + res.scale(getScale(pixelSize), tmpV3); return res; } }
\ No newline at end of file diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java index 127e260ca..6768b18c3 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java @@ -27,196 +27,192 @@ */ package jogamp.graph.font.typecast; -import java.util.ArrayList; - -import jogamp.graph.font.FontInt.GlyphInt; import jogamp.graph.font.typecast.ot.OTGlyph; import jogamp.graph.font.typecast.ot.Point; -import jogamp.graph.geom.plane.AffineTransform; -import jogamp.graph.geom.plane.Path2D; -import jogamp.graph.geom.plane.PathIterator; import com.jogamp.graph.curve.OutlineShape; -import com.jogamp.graph.font.Font; -import com.jogamp.graph.font.Font.Glyph; import com.jogamp.graph.geom.Vertex; import com.jogamp.graph.geom.Vertex.Factory; /** - * Factory to build a {@link com.jogamp.graph.geom.Path2D Path2D} from + * Factory to build an {@link OutlineShape} from * {@link jogamp.graph.font.typecast.ot.OTGlyph Glyph}s. + * + * http://www.freetype.org/freetype2/docs/glyphs/glyphs-3.html + * http://walon.org/pub/ttf/ttf_glyphs.htm */ public class TypecastRenderer { + private static final boolean DEBUG = false; - private static void getPaths(TypecastFont font, - CharSequence string, float pixelSize, AffineTransform transform, Path2D[] p) - { - if (string == null) { - return; - } - Font.Metrics metrics = font.getMetrics(); - float advanceTotal = 0; - float lineGap = metrics.getLineGap(pixelSize) ; - float ascent = metrics.getAscent(pixelSize) ; - float descent = metrics.getDescent(pixelSize) ; - if (transform == null) { - transform = new AffineTransform(); - } - AffineTransform t = new AffineTransform(); - - float advanceY = lineGap - descent + ascent; - float y = 0; - for (int i=0; i<string.length(); i++) - { - p[i] = new Path2D(); - p[i].reset(); - t.setTransform(transform); - char character = string.charAt(i); - if (character == '\n') { - y += advanceY; - advanceTotal = 0; - continue; - } else if (character == ' ') { - advanceTotal += font.getAdvanceWidth(Glyph.ID_SPACE, pixelSize); - continue; - } - Glyph glyph = font.getGlyph(character); - Path2D gp = ((GlyphInt)glyph).getPath(); - float scale = metrics.getScale(pixelSize); - t.translate(advanceTotal, y); - t.scale(scale, scale); - p[i].append(gp.iterator(t), false); - advanceTotal += glyph.getAdvance(pixelSize, true); - } + private static void addShapeMoveTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1) { + shape.closeLastOutline(false); + shape.addEmptyOutline(); + shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, p1.onCurve)); } - - public static ArrayList<OutlineShape> getOutlineShapes(TypecastFont font, CharSequence string, float pixelSize, AffineTransform transform, Factory<? extends Vertex> vertexFactory) { - Path2D[] paths = new Path2D[string.length()]; - getPaths(font, string, pixelSize, transform, paths); - - ArrayList<OutlineShape> shapes = new ArrayList<OutlineShape>(); - final int numGlyps = paths.length; - for (int index=0;index<numGlyps;index++) { - if(paths[index] == null){ - continue; - } - OutlineShape shape = new OutlineShape(vertexFactory); - shapes.add(shape); - PathIterator iterator = paths[index].iterator(transform); - if(null != iterator){ - while(!iterator.isDone()){ - float[] coords = new float[6]; - int segmentType = iterator.currentSegment(coords); - addPathVertexToOutline(shape, vertexFactory, coords, segmentType); - iterator.next(); - } - } - } - return shapes; + private static void addShapeLineTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1) { + shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, p1.onCurve)); } - private static void addPathVertexToOutline(OutlineShape shape, Factory<? extends Vertex> vertexFactory, float[] coords, int segmentType){ - switch(segmentType) { - case PathIterator.SEG_MOVETO: - shape.closeLastOutline(); - shape.addEmptyOutline(); - shape.addVertex(0, vertexFactory.create(coords, 0, 2, true)); - break; - case PathIterator.SEG_LINETO: - shape.addVertex(0, vertexFactory.create(coords, 0, 2, true)); - break; - case PathIterator.SEG_QUADTO: - shape.addVertex(0, vertexFactory.create(coords, 0, 2, false)); - shape.addVertex(0, vertexFactory.create(coords, 2, 2, true)); - break; - case PathIterator.SEG_CUBICTO: - shape.addVertex(0, vertexFactory.create(coords, 0, 2, false)); - shape.addVertex(0, vertexFactory.create(coords, 2, 2, false)); - shape.addVertex(0, vertexFactory.create(coords, 4, 2, true)); - break; - case PathIterator.SEG_CLOSE: - shape.closeLastOutline(); - break; - default: - throw new IllegalArgumentException("Unhandled Segment Type: "+segmentType); - } + private static void addShapeQuadTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, Point p2) { + shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, p1.onCurve)); + shape.addVertex(0, vertexFactory.create(p2.x, p2.y, 0, p2.onCurve)); + } + private static void addShapeQuadTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, + float p2x, float p2y, boolean p2OnCurve) { + shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, p1.onCurve)); + shape.addVertex(0, vertexFactory.create(p2x, p2y, 0, p2OnCurve)); } - /** - * Build a {@link com.jogamp.graph.geom.Path2D Path2D} from a - * {@link jogamp.graph.font.typecast.ot.OTGlyph Glyph}. This glyph path can then - * be transformed and rendered. - */ - public static Path2D buildPath(OTGlyph glyph) { + private static void addShapeCubicTo(final OutlineShape shape, Factory<? extends Vertex> vertexFactory, Point p1, Point p2, Point p3) { + shape.addVertex(0, vertexFactory.create(p1.x, p1.y, 0, p1.onCurve)); + shape.addVertex(0, vertexFactory.create(p2.x, p2.y, 0, p2.onCurve)); + shape.addVertex(0, vertexFactory.create(p3.x, p3.y, 0, p3.onCurve)); + } */ + + public static OutlineShape buildShape(char symbol, OTGlyph glyph, Factory<? extends Vertex> vertexFactory) { + // + // See Typecast: GlyphPathFactory.addContourToPath(..) + // if (glyph == null) { return null; } - Path2D glyphPath = new Path2D(); + final OutlineShape shape = new OutlineShape(vertexFactory); + buildShapeImpl(shape, symbol, glyph, vertexFactory); + shape.closeLastOutline(false); + return shape; + } + /** + private static void buildShapeImpl02(final OutlineShape shape, char symbol, OTGlyph glyph, Factory<? extends Vertex> vertexFactory) { // 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 startIndex = 0; int count = 0; for (int i = 0; i < glyph.getPointCount(); i++) { count++; - if (glyph.getPoint(i).endOfContour) { - addContourToPath(glyphPath, glyph, firstIndex, count); - firstIndex = i + 1; + if ( glyph.getPoint(i).endOfContour ) { + for(int j=0; j<count; j++) { + final Point p = glyph.getPoint(startIndex + j); + shape.addVertex(0, vertexFactory.create(p.x, p.y, 0, p.onCurve)); + } + shape.closeLastOutline(false); + startIndex = i + 1; count = 0; } } - return glyphPath; - } + } */ - private static void addContourToPath(Path2D gp, OTGlyph glyph, int startIndex, int count) { - int offset = 0; - while (offset < count) { - Point point = glyph.getPoint(startIndex + offset%count); - Point point_plus1 = glyph.getPoint(startIndex + (offset+1)%count); - Point point_plus2 = glyph.getPoint(startIndex + (offset+2)%count); - if(offset == 0) - { - gp.moveTo(point.x, point.y); - } + private static void buildShapeImpl(final OutlineShape shape, char symbol, OTGlyph glyph, Factory<? extends Vertex> vertexFactory) { + // 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 - 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; + 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); + } + if(offset == 0) { + addShapeMoveTo(shape, vertexFactory, p0); + // gp.moveTo(point.x, point.y); + } - if (point.onCurve) { - if (point_plus1.onCurve) { - // s = new Line2D.Float(point.x, point.y, point_plus1.x, point_plus1.y); - gp.lineTo( point_plus1.x, point_plus1.y ); - offset++; - } else { - if (point_plus2.onCurve) { - // s = new QuadCurve2D.Float( point.x, point.y, point_plus1.x, point_plus1.y, point_plus2.x, point_plus2.y); - gp.quadTo(point_plus1.x, point_plus1.y, point_plus2.x, point_plus2.y); - offset+=2; + 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) { + // 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(shape, vertexFactory, p1); + offset++; + } else { + if (p2.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(shape, vertexFactory, p1, p2); + offset+=2; + } else { + if (null != p3 && p3.onCurve) { + // 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(shape, vertexFactory, p1, + midValue(p1.x, p2.x), + midValue(p1.y, p2.y), true); + addShapeQuadTo(shape, vertexFactory, p2, p3); + offset+=3; + } 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(shape, vertexFactory, p1, + midValue(p1.x, p2.x), + midValue(p1.y, p2.y), true); + offset+=2; // Skip p2 as done in Typecast + } + } + } } else { - // s = new QuadCurve2D.Float(point.x,point.y,point_plus1.x,point_plus1.y, - // midValue(point_plus1.x, point_plus2.x), midValue(point_plus1.y, point_plus2.y)); - gp.quadTo(point_plus1.x, point_plus1.y, midValue(point_plus1.x, point_plus2.x), midValue(point_plus1.y, point_plus2.y)); - offset+=2; + if (!p1.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(shape, vertexFactory, p0, + midValue(p0.x, p1.x), midValue(p0.y, p1.y), true); + 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(shape, vertexFactory, p0, p1); + offset++; + } } } - } else { - if (point_plus1.onCurve) { - // s = new QuadCurve2D.Float(midValue(point_minus1.x, point.x), midValue(point_minus1.y, point.y), - // point.x, point.y, point_plus1.x, point_plus1.y); - //gp.curve3(point_plus1.x, point_plus1.y, point.x, point.y); - gp.quadTo(point.x, point.y, point_plus1.x, point_plus1.y); - offset++; - - } else { - // s = new QuadCurve2D.Float(midValue(point_minus1.x, point.x), midValue(point_minus1.y, point.y), point.x, point.y, - // midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y)); - //gp.curve3(midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y), point.x, point.y); - gp.quadTo(point.x, point.y, midValue(point.x, point_plus1.x), midValue(point.y, point_plus1.y)); - offset++; - } + shape.closeLastOutline(false); + startIndex = i + 1; + count = 0; } } } - private static int midValue(int a, int b) { - return a + (b - a)/2; + private static float midValue(float a, float b) { + return a + (b - a)/2f; } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/Point.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/Point.java index f1a090d68..0cac8ab44 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/ot/Point.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/Point.java @@ -18,7 +18,6 @@ public class Point { public int y = 0; public boolean onCurve = true; public boolean endOfContour = false; - public boolean touched = false; public Point(int x, int y, boolean onCurve, boolean endOfContour) { this.x = x; @@ -26,4 +25,8 @@ public class Point { this.onCurve = onCurve; this.endOfContour = endOfContour; } + + public String toString() { + return "P["+x+"/"+y+", on "+onCurve+", end "+endOfContour+"]"; + } } diff --git a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfCompositeDescript.java b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfCompositeDescript.java index 50e0fa339..fabc71a77 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfCompositeDescript.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/ot/table/GlyfCompositeDescript.java @@ -65,7 +65,7 @@ import java.util.ArrayList; */ public class GlyfCompositeDescript extends GlyfDescript { - private ArrayList<GlyfCompositeComp> _components = + private final ArrayList<GlyfCompositeComp> _components = new ArrayList<GlyfCompositeComp>(); public GlyfCompositeDescript( @@ -167,8 +167,9 @@ public class GlyfCompositeDescript extends GlyfDescript { @Override public int getContourCount() { - GlyfCompositeComp c = _components.get(_components.size()-1); - return c.getFirstContour() + _parentTable.getDescription(c.getGlyphIndex()).getContourCount(); + final GlyfCompositeComp c = _components.get(_components.size()-1); + final GlyfDescript d = _parentTable.getDescription(c.getGlyphIndex()); + return c.getFirstContour() + ( null != d ? d.getContourCount() : 0 ); } public int getComponentIndex(int i) { diff --git a/src/jogl/classes/jogamp/graph/font/typecast/t2/T2Interpreter.java b/src/jogl/classes/jogamp/graph/font/typecast/t2/T2Interpreter.java index 181ec7e10..73f26b27c 100644 --- a/src/jogl/classes/jogamp/graph/font/typecast/t2/T2Interpreter.java +++ b/src/jogl/classes/jogamp/graph/font/typecast/t2/T2Interpreter.java @@ -39,11 +39,11 @@ public class T2Interpreter { private static final int SUBR_STACK_LIMIT = 10; private static final int TRANSIENT_ARRAY_ELEMENT_COUNT = 32; - private Number[] _argStack = new Number[ARGUMENT_STACK_LIMIT]; + private final Number[] _argStack = new Number[ARGUMENT_STACK_LIMIT]; private int _argStackIndex = 0; - private int[] _subrStack = new int[SUBR_STACK_LIMIT]; + private final int[] _subrStack = new int[SUBR_STACK_LIMIT]; private int _subrStackIndex = 0; - private Number[] _transientArray = new Number[TRANSIENT_ARRAY_ELEMENT_COUNT]; + private final Number[] _transientArray = new Number[TRANSIENT_ARRAY_ELEMENT_COUNT]; private ArrayList<Point> _points; |