diff options
Diffstat (limited to 'src/jogamp/graph')
-rw-r--r-- | src/jogamp/graph/font/JavaFontLoader.java | 111 | ||||
-rw-r--r-- | src/jogamp/graph/font/typecast/TypecastFont.java | 178 | ||||
-rw-r--r-- | src/jogamp/graph/font/typecast/TypecastFontFactory.java | 65 | ||||
-rw-r--r-- | src/jogamp/graph/font/typecast/TypecastGlyph.java | 269 | ||||
-rw-r--r-- | src/jogamp/graph/font/typecast/TypecastMetrics.java | 87 | ||||
-rw-r--r-- | src/jogamp/graph/font/typecast/TypecastRenderer.java | 162 |
6 files changed, 872 insertions, 0 deletions
diff --git a/src/jogamp/graph/font/JavaFontLoader.java b/src/jogamp/graph/font/JavaFontLoader.java new file mode 100644 index 000000000..f6954944d --- /dev/null +++ b/src/jogamp/graph/font/JavaFontLoader.java @@ -0,0 +1,111 @@ +/** + * 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; + +public class JavaFontLoader { + + static String javaFontPath; + static + { + javaFontPath = System.getProperty("java.home") + "/lib/fonts/"; + } + + public static final int MAX_BITMAP_FONT_SIZE = 120; + + public static final int MONOSPACED = 1; + public static final int SERIF = 2; + public static final int SANSERIF = 3; + public static final int CURSIVE = 4; + public static final int FANTASY = 5; + + final static String availableJavaFontNames[] = + { + "Lucida Bright Regular", + "Lucida Bright Italic", + "Lucida Bright Demibold", + "Lucida Bright Demibold Italic", + "Lucida Sans Regular", + "Lucida Sans Demibold", + "Lucida Sans Typewriter Regular", + "Lucida Sans Typewriter Bold", + }; + static public String[] getAvailableNames() + { + return availableJavaFontNames; + } + + final static String availableJavaFontFileNames[] = + { + "LucidaBrightRegular.ttf", + "LucidaBrightItalic.ttf", + "LucidaBrightDemiBold.ttf", + "LucidaBrightDemiItalic.ttf", + "LucidaSansRegular.ttf", + "LucidaSansDemiBold.ttf", + "LucidaTypewriterRegular.ttf", + "LucidaTypewriterBold.ttf", + }; + + static public String get(int type) + { + String font = null; + + switch (type) + { + case MONOSPACED: + font = getByName("Lucida Sans Typewriter Regular"); + break; + case SERIF: + font = getByName("Lucida Bright Regular"); + break; + case SANSERIF: + font = getByName("Lucida Sans Regular"); + break; + case CURSIVE: + font = getByName("Lucida Bright Regular"); + break; + case FANTASY: + font = getByName("Lucida Sans Regular"); + break; + } + + return font; + } + + static public String getByName(String name) + { + for (int i=0; i<availableJavaFontNames.length; i++) + { + if (name.equals(availableJavaFontNames[i]) == true) + { + return javaFontPath+availableJavaFontFileNames[i]; + } + } + return null; + } +} diff --git a/src/jogamp/graph/font/typecast/TypecastFont.java b/src/jogamp/graph/font/typecast/TypecastFont.java new file mode 100644 index 000000000..7cc80cc13 --- /dev/null +++ b/src/jogamp/graph/font/typecast/TypecastFont.java @@ -0,0 +1,178 @@ +/** + * 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.typecast; + +import java.io.File; +import java.io.IOException; + +import jogamp.graph.font.JavaFontLoader; + +import net.java.dev.typecast.ot.OTFont; +import net.java.dev.typecast.ot.OTFontCollection; +import net.java.dev.typecast.ot.table.CmapFormat; +import net.java.dev.typecast.ot.table.CmapTable; +import net.java.dev.typecast.ot.table.ID; + +import com.jogamp.common.util.IntObjectHashMap; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.geom.AABBox; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.geom.plane.Path2D; +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Point; + +class TypecastFont implements Font { + static final boolean DEBUG = false; + + final Point.Factory<? extends PointTex> pointFactory; + final OTFontCollection fontset; + final OTFont font; + final int size; + Metrics metrics; + final CmapFormat cmapFormat; + int cmapentries; + // final IntIntHashMap char2Code; + IntObjectHashMap char2Glyph; + + public static TypecastFont create(Point.Factory<? extends PointTex> factory, String name, int size) { + String path = JavaFontLoader.getByName(name); + OTFontCollection fontset; + try { + fontset = OTFontCollection.create(new File(path)); + return new TypecastFont(factory, fontset, size); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public TypecastFont(Point.Factory<? extends PointTex> factory, OTFontCollection fontset, int size) { + this.pointFactory = factory; + this.fontset = fontset; + this.font = fontset.getFont(0); + this.size = size; + + CmapTable cmapTable = font.getCmapTable(); + CmapFormat _cmapFormat = null; + /* + if(null == _cmapFormat) { + _cmapFormat = cmapTable.getCmapFormat(ID.platformMacintosh, ID.encodingASCII); + } */ + if(null == _cmapFormat) { + // default unicode + _cmapFormat = cmapTable.getCmapFormat(ID.platformMicrosoft, ID.encodingUnicode); + } + if(null == _cmapFormat) { + // maybe a symbol font ? + _cmapFormat = cmapTable.getCmapFormat(ID.platformMicrosoft, ID.encodingSymbol); + } + if(null == _cmapFormat) { + throw new RuntimeException("Cannot find a suitable cmap table for font "+font); + } + cmapFormat = _cmapFormat; + + cmapentries = 0; + for (int i = 0; i < cmapFormat.getRangeCount(); ++i) { + CmapFormat.Range range = cmapFormat.getRange(i); + cmapentries += range.getEndCode() - range.getStartCode() + 1; // end included + } + if(DEBUG) { + System.err.println("num glyphs: "+font.getNumGlyphs()); + System.err.println("num cmap entries: "+cmapentries); + } + + /* + char2Code = new IntIntHashMap(cmapentries + cmapentries/4); + for (int i = 0; i < cmapFormat.getRangeCount(); ++i) { + CmapFormat.Range range = cmapFormat.getRange(i); + for (int j = range.getStartCode(); j <= range.getEndCode(); ++j) { + final int code = cmapFormat.mapCharCode(j); + char2Code.put(j, code); + if(code < 50) { + System.err.println(" char: " + (int)j + " ( " + (char)j +" ) -> " + code); + } + } + } + */ + char2Glyph = new IntObjectHashMap(cmapentries + cmapentries/4); + } + + public String getName() { + return fontset.getFileName(); + } + + public float getSize() { + return size; + } + + public Metrics getMetrics() { + if (metrics == null) { + metrics = new TypecastMetrics(this); + } + return metrics; + } + + public Glyph getGlyph(char symbol) { + TypecastGlyph result = (TypecastGlyph) char2Glyph.get(symbol); + if (null == result) { + // final short code = (short) char2Code.get(symbol); + final short code = (short) cmapFormat.mapCharCode(symbol); + net.java.dev.typecast.ot.OTGlyph glyph = font.getGlyph(code); + final Path2D path = TypecastRenderer.buildPath(glyph); + result = new TypecastGlyph(this, symbol, code, glyph.getBBox(), glyph.getAdvanceWidth(), path); + if(DEBUG) { + System.err.println("New glyph: " + (int)symbol + " ( " + (char)symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + path); + } + char2Glyph.put(symbol, result); + } + return result; + } + + public void getOutline(String string, AffineTransform transform, Path2D[] result) { + TypecastRenderer.getOutline(pointFactory, this, string, transform, result); + } + + public float getStringWidth(String string) { + // return 0f; // FIXME font.getStringWidthForPixelSize(string, size); + throw new RuntimeException("n/a"); + } + + public float getStringHeight(String string) { + // return 0f; // FIXME font.getStringHeightForPixelSize(string, size); + throw new RuntimeException("n/a"); + } + + public AABBox getStringBounds(CharSequence string) { + // return null; // FIXME font.getStringBoundsForPixelSize(string, size); + throw new RuntimeException("n/a"); + } + + final public int getNumGlyphs() { + return font.getNumGlyphs(); + } +}
\ No newline at end of file diff --git a/src/jogamp/graph/font/typecast/TypecastFontFactory.java b/src/jogamp/graph/font/typecast/TypecastFontFactory.java new file mode 100644 index 000000000..f66772029 --- /dev/null +++ b/src/jogamp/graph/font/typecast/TypecastFontFactory.java @@ -0,0 +1,65 @@ +/** + * 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.typecast; + +import java.util.HashMap; +import java.util.Map; + +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.geom.Point.Factory; +import com.jogamp.graph.geom.PointTex; + + +public class TypecastFontFactory implements FontFactory { + + Map<String, Font> fonts = new HashMap<String, Font>(); + + public Font createFont(Factory<? extends PointTex> factory, String name, int size) { + Font result = fonts.get(name + ":"+size); + if (result == null) { + result = TypecastFont.create(factory, name, size); + if(result != null) { + fonts.put(name+":"+size, result); + } + } + return result; + } + + + public Font createFont(Factory<? extends PointTex> factory, + String[] families, + String style, + String variant, + String weight, + String size) { + throw new Error("not implemented"); + } + + +}
\ No newline at end of file diff --git a/src/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogamp/graph/font/typecast/TypecastGlyph.java new file mode 100644 index 000000000..faca8c779 --- /dev/null +++ b/src/jogamp/graph/font/typecast/TypecastGlyph.java @@ -0,0 +1,269 @@ +/** + * 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.typecast; + +import com.jogamp.graph.font.Font; +import com.jogamp.graph.geom.AABBox; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.geom.plane.Path2D; + +public class TypecastGlyph implements Font.Glyph { + public class Advance + { + Font font; + float advance; + float advances[]; // in pixels + float sizes[]; + float advanceCached = -1; // in pixels + float sizeCached = -1; + + public Advance(Font font, float advance) + { + this.font = font; + this.advance = advance; + + this.advances = new float[0]; + this.sizes = new float[0]; + } + + public float getScaleForPixelSize(float pixelSize) + { + return this.font.getMetrics().getScaleForPixelSize(pixelSize); + } + + public void add(float advance, float size) + { + float advancesNew[] = new float[this.advances.length+1]; + float sizesNew[] = new float[this.sizes.length+1]; + + for (int i=0; i<this.advances.length; i++) { + advancesNew[i] = this.advances[i]; + sizesNew[i] = this.sizes[i]; + } + + advancesNew[advancesNew.length-1] = advance; + sizesNew[sizesNew.length-1] = size; + + this.advances = advancesNew; + this.sizes = sizesNew; + } + + public float get(float size, boolean useFrationalMetrics) + { + if (this.sizeCached != size) { + this.sizeCached = size; + + float value = (this.advance * getScaleForPixelSize(size)); + if (useFrationalMetrics == false) { + //value = (float)Math.ceil(value); + // value = (int)value; + value = (int) ( value + 0.5f ) ; // TODO: check + } + + if (true) + { + for (int i=0; i<this.advances.length; i++) + { + if (this.sizes[i] == size) + { + value = this.advances[i]; + break; + } + } + } + + this.advanceCached = value; + } + return this.advanceCached; + } + + public String toString() + { + String string = ""; + for (int i=0; i<this.advances.length; i++) { + string += " size: "+this.sizes[i]+" advance: "+this.advances[i]+"\n"; + } + if (string.length() > 0) { + string = "\n advances: \n"+string; + } + return "\nAdvance:"+ + "\n advance: "+this.advance+ + string; + } + } + + public class Metrics + { + AABBox bbox; + AABBox bbox_sized; + Advance advance; + + public Metrics(Font font, AABBox bbox, float advance) + { + this.bbox = bbox; + this.advance = new Advance(font, advance); + } + + public float getScaleForPixelSize(float pixelSize) + { + return this.advance.getScaleForPixelSize(pixelSize); + } + + public AABBox getBBox() + { + return this.bbox; + } + + public void addAdvance(float advance, float size) + { + this.advance.add(advance, size); + } + + public float getAdvanceForPixelSize(float size, boolean useFrationalMetrics) + { + return this.advance.get(size, useFrationalMetrics); + } + + public String toString() + { + return "\nMetrics:"+ + "\n bbox: "+this.bbox+ + this.advance; + } + } + + public static final short INVALID_ID = (short)((1 << 16) - 1); + public static final short MAX_ID = (short)((1 << 16) - 2); + + private final Font font; + + 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) { + 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.id = id; + this.advance = advance; + this.metrics = new Metrics(this.font, bbox, this.advance); + } + + public Font getFont() { + return this.font; + } + + public char getSymbol() { + return this.symbol; + } + + AABBox getBBoxUnsized() { + return this.metrics.getBBox(); + } + + public AABBox getBBox() { + return this.metrics.getBBox(); + } + + public Metrics getMetrics() { + return this.metrics; + } + + public short getID() { + return this.id; + } + + public float getScaleForPixelSize(float pixelSize) { + return this.metrics.getScaleForPixelSize(pixelSize); + } + + public AABBox getBBox(float size) { + AABBox newBox = getBBox().clone(); + newBox.scale(size); + return newBox; + } + + public AABBox getBBoxForPixelSize(float pixelSize) { + return getBBox(getScaleForPixelSize(pixelSize)); + } + + protected void addAdvance(float advance, float size) { + this.metrics.addAdvance(advance, size); + } + + public float getAdvanceForPixelSize(float size, boolean useFrationalMetrics) { + return this.metrics.getAdvanceForPixelSize(size, useFrationalMetrics); + } + + public float getAdvance() { + return getAdvanceForPixelSize(font.getSize(), false); + } + + public Path2D getPath() { + return getPath(getScaleForPixelSize(font.getSize())); + } + + private Path2D getPath(float size) + { + if (this.numberSized != size) { + this.numberSized = size; + this.pathSized = AffineTransform.getScaleInstance(null, size, size).createTransformedShape(getPath()); + } + return this.pathSized; + } + + public Path2D getPathForPixelSize(float pixelSize) { + return getPath(getScaleForPixelSize(pixelSize)); + } + + public Path2D getNormalPath() { + return this.path; + } + +} diff --git a/src/jogamp/graph/font/typecast/TypecastMetrics.java b/src/jogamp/graph/font/typecast/TypecastMetrics.java new file mode 100644 index 000000000..541ed90d8 --- /dev/null +++ b/src/jogamp/graph/font/typecast/TypecastMetrics.java @@ -0,0 +1,87 @@ +/** + * 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.typecast; + +import net.java.dev.typecast.ot.table.HeadTable; +import net.java.dev.typecast.ot.table.HheaTable; + +import com.jogamp.graph.font.Font.Metrics; +import com.jogamp.graph.geom.AABBox; + +class TypecastMetrics implements Metrics { + private final TypecastFont fontImpl; + + // HeadTable + private final float unitsPerEM_Inv; + private final float unitsPerEM_Inv_sized; + private final AABBox bbox_sized; + + // HheaTable + private final float ascend_sized; + private final float descent_sized; + private final float linegap_sized; + + public TypecastMetrics(TypecastFont fontImpl) { + this.fontImpl = fontImpl; + final HeadTable headTable = this.fontImpl.font.getHeadTable(); + unitsPerEM_Inv = 1.0f / ( (float) headTable.getUnitsPerEm() ); + unitsPerEM_Inv_sized = this.fontImpl.size * unitsPerEM_Inv; + int maxWidth = headTable.getXMax() - headTable.getXMin(); + int maxHeight = headTable.getYMax() - headTable.getYMin(); + float lowx= headTable.getXMin(); + float lowy = -(headTable.getYMin()+maxHeight); + float highx = lowx + maxWidth; + float highy = lowy + maxHeight; + bbox_sized = new AABBox(lowx, lowy, 0, highx, highy, 0); // invert + bbox_sized.scale(unitsPerEM_Inv_sized); + + final HheaTable hheaTable = this.fontImpl.font.getHheaTable(); + ascend_sized = unitsPerEM_Inv_sized * -hheaTable.getAscender(); // invert + descent_sized = unitsPerEM_Inv_sized * -hheaTable.getDescender(); // invert + linegap_sized = unitsPerEM_Inv_sized * -hheaTable.getLineGap(); // invert + } + + public final float getAscent() { + return ascend_sized; + } + public final float getDescent() { + return descent_sized; + } + public final float getLineGap() { + return linegap_sized; + } + public final float getScale() { + return unitsPerEM_Inv_sized; + } + public float getScaleForPixelSize(float pixelSize) { + return pixelSize * unitsPerEM_Inv; + } + public final AABBox getBBox() { + return bbox_sized; + } +}
\ No newline at end of file diff --git a/src/jogamp/graph/font/typecast/TypecastRenderer.java b/src/jogamp/graph/font/typecast/TypecastRenderer.java new file mode 100644 index 000000000..7b36d22b5 --- /dev/null +++ b/src/jogamp/graph/font/typecast/TypecastRenderer.java @@ -0,0 +1,162 @@ +/** + * 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.typecast; + +import com.jogamp.graph.font.Font; +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.geom.plane.Path2D; +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Point.Factory; + +import net.java.dev.typecast.ot.Point; +import net.java.dev.typecast.ot.OTGlyph; + +/** + * Factory to build a {@link com.jogamp.graph.geom.Path2D Path2D} from + * {@link net.java.dev.typecast.ot.OTGlyph Glyph}s. + */ +public class TypecastRenderer { + + public static void getOutline(Factory<? extends PointTex> factory, TypecastFont font, + String string, AffineTransform transform, Path2D[] p) + { + if (string == null) { + return; + } + Font.Metrics metrics = font.getMetrics(); + float advanceTotal = 0; + float lineGap = metrics.getLineGap() ; + float ascent = metrics.getAscent() ; + float descent = metrics.getDescent() ; + if (transform == null) { + transform = new AffineTransform(factory); + } + AffineTransform t = new AffineTransform(factory); + + 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; + } + TypecastGlyph glyph = (TypecastGlyph) font.getGlyph(character); + Path2D gp = glyph.getNormalPath(); + float scale = metrics.getScale(); + t.translate(advanceTotal, y); + t.scale(scale, scale); + p[i].append(gp.iterator(t), false); + advanceTotal += glyph.getAdvanceForPixelSize(font.getSize(), true); + } + } + + /** + * Build a {@link com.jogamp.graph.geom.Path2D Path2D} from a + * {@link net.java.dev.typecast.ot.OTGlyph Glyph}. This glyph path can then + * be transformed and rendered. + */ + public static Path2D buildPath(OTGlyph glyph) { + + if (glyph == null) { + return null; + } + + Path2D glyphPath = new Path2D(); + + // 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; + for (int i = 0; i < glyph.getPointCount(); i++) { + count++; + if (glyph.getPoint(i).endOfContour) { + addContourToPath(glyphPath, glyph, firstIndex, count); + firstIndex = 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); + } + + 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; + } 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; + } + } + } 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++; + } + } + } + } + + private static int midValue(int a, int b) { + return a + (b - a)/2; + } +} |