summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/jogl/classes/com/jogamp/graph/curve/OutlineShape.java307
-rwxr-xr-xsrc/jogl/classes/com/jogamp/graph/curve/Region.java128
-rwxr-xr-xsrc/jogl/classes/com/jogamp/graph/curve/RegionFactory.java62
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java113
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java167
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java103
-rw-r--r--src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java216
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/Font.java82
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/FontFactory.java80
-rw-r--r--src/jogl/classes/com/jogamp/graph/font/FontSet.java60
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/AABBox.java299
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Outline.java176
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Triangle.java79
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/Vertex.java80
-rw-r--r--src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java178
-rwxr-xr-xsrc/jogl/classes/com/jogamp/graph/math/Quaternion.java382
-rwxr-xr-xsrc/jogl/classes/com/jogamp/graph/math/VectorUtil.java295
-rwxr-xr-xsrc/jogl/classes/jogamp/graph/curve/opengl/RegionRendererImpl01.java206
-rw-r--r--src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java188
-rw-r--r--src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PES2.java385
-rw-r--r--src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java185
-rw-r--r--src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.fp99
-rw-r--r--src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.vp13
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java81
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/GraphVertex.java120
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/HEdge.java130
-rw-r--r--src/jogl/classes/jogamp/graph/curve/tess/Loop.java373
-rw-r--r--src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java161
-rw-r--r--src/jogl/classes/jogamp/graph/curve/text/GlyphString.java163
-rw-r--r--src/jogl/classes/jogamp/graph/font/FontConstructor.java34
-rw-r--r--src/jogl/classes/jogamp/graph/font/FontInt.java50
-rw-r--r--src/jogl/classes/jogamp/graph/font/JavaFontLoader.java129
-rw-r--r--src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java132
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt21
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt211
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt177
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE.txt96
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/README.txt15
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt4
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttfbin0 -> 339320 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttfbin0 -> 362784 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttfbin0 -> 421172 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttfbin0 -> 415424 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttfbin0 -> 346940 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttfbin0 -> 372728 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttfbin0 -> 359668 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttfbin0 -> 389744 bytes
-rw-r--r--src/jogl/classes/jogamp/graph/font/fonts/ubuntu/copyright.txt5
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java268
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java53
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java232
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java83
-rw-r--r--src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java163
-rw-r--r--src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java580
-rw-r--r--src/jogl/classes/jogamp/graph/geom/plane/IllegalPathStateException.java34
-rw-r--r--src/jogl/classes/jogamp/graph/geom/plane/NoninvertibleTransformException.java31
-rw-r--r--src/jogl/classes/jogamp/graph/geom/plane/Path2D.java428
-rw-r--r--src/jogl/classes/jogamp/graph/geom/plane/PathIterator.java42
-rw-r--r--src/jogl/classes/jogamp/graph/math/MathFloat.java45
-rw-r--r--src/jogl/classes/jogamp/graph/math/plane/Crossing.java897
-rw-r--r--src/jogl/classes/org/apache/harmony/misc/HashCode.java203
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java156
-rwxr-xr-xsrc/test/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java169
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java124
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java120
-rwxr-xr-xsrc/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java75
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java75
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java52
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java264
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java61
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java67
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java76
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java229
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java69
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java109
-rw-r--r--src/test/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java39
-rw-r--r--src/typecast/net/java/dev/typecast/ot/Disassembler.java109
-rw-r--r--src/typecast/net/java/dev/typecast/ot/Fixed.java852
-rw-r--r--src/typecast/net/java/dev/typecast/ot/Mnemonic.java397
-rw-r--r--src/typecast/net/java/dev/typecast/ot/OTFont.java274
-rw-r--r--src/typecast/net/java/dev/typecast/ot/OTFontCollection.java169
-rw-r--r--src/typecast/net/java/dev/typecast/ot/OTGlyph.java168
-rw-r--r--src/typecast/net/java/dev/typecast/ot/Point.java29
-rw-r--r--src/typecast/net/java/dev/typecast/ot/mac/ResourceData.java45
-rw-r--r--src/typecast/net/java/dev/typecast/ot/mac/ResourceFile.java77
-rw-r--r--src/typecast/net/java/dev/typecast/ot/mac/ResourceHeader.java61
-rw-r--r--src/typecast/net/java/dev/typecast/ot/mac/ResourceMap.java83
-rw-r--r--src/typecast/net/java/dev/typecast/ot/mac/ResourceReference.java81
-rw-r--r--src/typecast/net/java/dev/typecast/ot/mac/ResourceType.java82
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/BaseTable.java435
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CffStandardStrings.java424
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CffTable.java620
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Charstring.java33
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CharstringType2.java235
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ClassDef.java33
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat1.java39
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat2.java37
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapFormat.java134
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapFormat0.java92
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapFormat2.java173
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapFormat4.java165
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapFormat6.java87
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapFormatUnknown.java54
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapIndexEntry.java117
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CmapTable.java161
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Coverage.java83
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CoverageFormat1.java88
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CoverageFormat2.java89
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/CvtTable.java61
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Device.java50
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/DirectoryEntry.java115
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/DsigEntry.java43
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/DsigTable.java69
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Feature.java85
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/FeatureList.java118
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/FeatureRecord.java88
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/FeatureTags.java63
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/FpgmTable.java46
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GaspRange.java45
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GaspTable.java63
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeComp.java200
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeDescript.java202
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GlyfDescript.java124
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GlyfSimpleDescript.java245
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GlyfTable.java132
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GlyphDescription.java86
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GposTable.java66
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/GsubTable.java181
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/HdmxTable.java130
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/HeadTable.java205
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/HheaTable.java135
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/HmtxTable.java141
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ID.java399
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/KernSubtable.java49
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat0.java47
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat2.java42
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/KernTable.java62
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/KerningPair.java44
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LangSys.java105
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LangSysRecord.java88
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Ligature.java85
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LigatureSet.java85
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LigatureSubst.java73
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LigatureSubstFormat1.java95
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LocaTable.java77
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Lookup.java110
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LookupList.java108
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LookupSubtable.java60
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LookupSubtableFactory.java64
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/LtshTable.java68
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/MaxpTable.java162
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/NameRecord.java145
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/NameTable.java131
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Os2Table.java357
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Panose.java96
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/PcltTable.java105
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/PostTable.java422
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/PrepTable.java46
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Program.java40
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/RangeRecord.java87
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Script.java118
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ScriptList.java115
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ScriptRecord.java88
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/ScriptTags.java61
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/SignatureBlock.java46
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/SingleSubst.java81
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat1.java92
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat2.java97
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/TTCHeader.java59
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/Table.java67
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/TableDirectory.java129
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/TableException.java46
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/TableFactory.java184
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/VdmxTable.java197
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/VheaTable.java147
-rw-r--r--src/typecast/net/java/dev/typecast/ot/table/VmtxTable.java112
-rw-r--r--src/typecast/net/java/dev/typecast/t2/T2Interpreter.java1043
-rw-r--r--src/typecast/net/java/dev/typecast/t2/T2Mnemonic.java86
-rw-r--r--src/typecast/net/java/dev/typecast/tt/engine/GraphicsState.java50
-rw-r--r--src/typecast/net/java/dev/typecast/tt/engine/Interpreter.java1357
-rw-r--r--src/typecast/net/java/dev/typecast/tt/engine/Parser.java192
181 files changed, 26367 insertions, 0 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
new file mode 100755
index 000000000..827717aa5
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java
@@ -0,0 +1,307 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.curve;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+import com.jogamp.graph.curve.tess.CDTriangulator2D;
+
+/** A Generic shape objects which is defined by a list of Outlines.
+ * This Shape can be transformed to Triangulations.
+ * The list of triangles generated are render-able by a Region object.
+ * The triangulation produced by this Shape will define the
+ * closed region defined by the outlines.
+ *
+ * One or more OutlineShape Object can be associated to a region
+ * this is left as a high-level representation of the Objects. For
+ * optimizations, flexibility requirements for future features.
+ *
+ * <br><br>
+ * Example to creating an Outline Shape:
+ * <pre>
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ addEnptyOutline()
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ * </pre>
+ *
+ * The above will create two outlines each with three vertices. By adding these two outlines to
+ * the OutlineShape, we are stating that the combination of the two outlines represent the shape.
+ * <br>
+ *
+ * To specify that the shape is curved at a region, the on-curve flag should be set to false
+ * for the vertex that is in the middle of the curved region (if the curved region is defined by 3
+ * vertices (quadratic curve).
+ * <br>
+ * In case the curved region is defined by 4 or more vertices the middle vertices should both have
+ * the on-curve flag set to false.
+ *
+ * <br>Example: <br>
+ * <pre>
+ addVertex(0,0, true);
+ addVertex(0,1, false);
+ addVertex(1,1, false);
+ addVertex(1,0, true);
+ * </pre>
+ *
+ * The above snippet defines a cubic nurbs curve where (0,1 and 1,1)
+ * do not belong to the final rendered shape.
+ *
+ * <i>Implementation Notes:</i><br>
+ * <ul>
+ * <li> The first vertex of any outline belonging to the shape should be on-curve</li>
+ * <li> Intersections between off-curved parts of the outline is not handled</li>
+ * </ul>
+ *
+ * @see Outline
+ * @see Region
+ */
+public class OutlineShape {
+
+ public static final int QUADRATIC_NURBS = 10;
+ private final Vertex.Factory<? extends Vertex> vertexFactory;
+
+ /** The list of {@link Outline}s that are part of this
+ * outline shape.
+ */
+ private ArrayList<Outline> outlines = new ArrayList<Outline>(3);
+
+ /** Create a new Outline based Shape
+ */
+ public OutlineShape(Vertex.Factory<? extends Vertex> factory) {
+ vertexFactory = factory;
+ outlines.add(new Outline());
+ }
+
+ /** Returns the associated vertex factory of this outline shape
+ * @return Vertex.Factory object
+ */
+ public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
+
+ /** Add a new empty {@link Outline}
+ * to the shape, this new outline will
+ * be placed at the end of the outline list.
+ *
+ * After a call to this function all new vertices added
+ * will belong to the new outline
+ */
+ public void addEmptyOutline(){
+ outlines.add(new Outline());
+ }
+
+ /** Adds an {@link Outline} to the OutlineShape object
+ * if last outline of the shape is empty, it will replace
+ * that last Outline with the new one. If outline is empty,
+ * it will do nothing.
+ * @param outline an Outline object
+ */
+ public void addOutline(Outline outline){
+ if(outline.isEmpty()){
+ return;
+ }
+ if(getLastOutline().isEmpty()){
+ outlines.remove(getLastOutline());
+ }
+ outlines.add(outline);
+ }
+
+ /** Adds a vertex to the last open outline in the
+ * shape.
+ * @param v the vertex to be added to the OutlineShape
+ */
+ public final void addVertex(Vertex v){
+ getLastOutline().addVertex(v);
+ }
+
+ /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex. The 2D vertex will be represented as Z=0.
+ *
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, onCurve);
+ }
+
+ /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex.
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param z the z coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, float z, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, z, onCurve);
+ }
+
+ /** Add a vertex to the last outline by passing a float array and specifying the
+ * offset and length in which. The attributes of the vertex are located.
+ * The attributes should be continuous (stride = 0).
+ * Attributes which value are not set (when length less than 3)
+ * are set implicitly to zero.
+ * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
+ * @param offset the offset in the buffer to the x coordinate
+ * @param length the number of attributes to pick from the buffer (maximum 3)
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, coordsBuffer, offset, length, onCurve);
+ }
+
+ /** Closes the last outline in the shape
+ * if last vertex is not equal to first vertex.
+ * A new temp vertex is added at the end which
+ * is equal to the first.
+ */
+ public void closeLastOutline(){
+ getLastOutline().setClosed(true);
+ }
+
+ /** Get the last added outline to the list
+ * of outlines that define the shape
+ * @return the last outline
+ */
+ public final Outline getLastOutline(){
+ return outlines.get(outlines.size()-1);
+ }
+ /** Make sure that the outlines represent
+ * the specified destinationType, if not
+ * transform outlines to destination type.
+ * @param destinationType The curve type needed
+ */
+ public void transformOutlines(int destinationType){
+ if(destinationType == QUADRATIC_NURBS){
+ transformOutlinesQuadratic();
+ }
+ }
+
+ private void transformOutlinesQuadratic(){
+ ArrayList<Outline> newOutlines = new ArrayList<Outline>(3);
+
+ /**loop over the outlines and make sure no
+ * adj off-curve vertices
+ */
+ for(Outline outline:outlines){
+ Outline newOutline = new Outline();
+
+ ArrayList<Vertex> vertices = outline.getVertices();
+ int size =vertices.size()-1;
+ for(int i=0;i<size;i++){
+ Vertex currentVertex = vertices.get(i);
+ Vertex nextVertex = vertices.get((i+1)%size);
+ if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
+ newOutline.addVertex(currentVertex);
+
+ float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
+ newOutline.addVertex(vertexFactory, newCoords, 0, 3, true);
+ }
+ else {
+ newOutline.addVertex(currentVertex);
+ }
+ }
+ newOutlines.add(newOutline);
+ }
+ outlines = newOutlines;
+ }
+
+ private void generateVertexIds(){
+ int maxVertexId = 0;
+ for(Outline outline:outlines){
+ ArrayList<Vertex> vertices = outline.getVertices();
+ for(Vertex vert:vertices){
+ vert.setId(maxVertexId);
+ maxVertexId++;
+ }
+ }
+ }
+
+ /** @return the list of vertices associated with the
+ * {@code Outline} list of this object
+ */
+ public ArrayList<Vertex> getVertices(){
+ ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+ for(Outline polyline:outlines){
+ vertices.addAll(polyline.getVertices());
+ }
+ return vertices;
+ }
+
+ /** Triangulate the outline shape generating a list of triangles
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(){
+ return triangulate(0.5f);
+ }
+
+ /**Triangulate the {@link OutlineShape} generating a list of triangles
+ * @param sharpness defines the curvature strength around the off-curve vertices.
+ * defaults to 0.5f
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(float sharpness){
+ if(outlines.size() == 0){
+ return null;
+ }
+ sortOutlines();
+ generateVertexIds();
+
+ CDTriangulator2D triangulator2d = new CDTriangulator2D(sharpness);
+ for(int index = 0; index< outlines.size();index++){
+ Outline outline = outlines.get(index);
+ triangulator2d.addCurve(outline);
+ }
+
+ ArrayList<Triangle> triangles = triangulator2d.generateTriangulation();
+ triangulator2d.reset();
+
+ return triangles;
+ }
+
+ /** Sort the outlines from large
+ * to small depending on the AABox
+ */
+ private void sortOutlines() {
+ Collections.sort(outlines);
+ Collections.reverse(outlines);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java
new file mode 100755
index 000000000..051cb1c38
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.curve;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.PMVMatrix;
+
+/** A Region is the OGL binding of one or more OutlineShapes
+ * Defined by its vertices and generated triangles. The Region
+ * defines the final shape of the OutlineShape(s), which shall produced a shaded
+ * region on the screen.
+ *
+ * Implementations of the Region shall take care of the OGL
+ * binding of the depending on its context, profile.
+ *
+ * @see RegionFactory, OutlineShape
+ */
+public interface Region {
+ /** The vertices index in an OGL object
+ */
+ public static int VERTEX_ATTR_IDX = 0;
+
+ /** The Texture Coord index in an OGL object
+ */
+ public static int TEXCOORD_ATTR_IDX = 1;
+
+ /** single pass rendering, fast, but AA might not be perfect */
+ public static int SINGLE_PASS = 1;
+
+ /** two pass rendering, slower and more resource hungry (FBO), but AA is perfect */
+ public static int TWO_PASS = 2;
+
+ /** Updates a graph region by updating the ogl related
+ * objects for use in rendering. if called for the first time
+ * it initialize the objects.
+ */
+ public void update();
+
+ /** Renders the associated OGL objects specifying
+ * current width/hight of window for multi pass rendering
+ * of the region.
+ * @param matrix current {@link PMVMatrix}.
+ * @param vp_width current screen width
+ * @param vp_height current screen height
+ * @param width texture width for mp rendering
+ *
+ * @see update()
+ */
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width);
+
+ /** Adds a list of {@link Triangle} objects to the Region
+ * These triangles are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param tris an arraylist of triangle objects
+ *
+ * @see update()
+ */
+ public void addTriangles(ArrayList<Triangle> tris);
+
+ /** Get the current number of vertices associated
+ * with this region. This number is not necessary equal to
+ * the OGL binded number of vertices.
+ * @return vertices count
+ *
+ * @see isDirty()
+ */
+ public int getNumVertices();
+
+ /** Adds a list of {@link Vertex} objects to the Region
+ * These vertices are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param verts an arraylist of vertex objects
+ *
+ * @see update()
+ */
+ public void addVertices(ArrayList<Vertex> verts);
+
+ /** Check if this region is dirty. A region is marked dirty
+ * when new Vertices, Triangles, and or Lines are added after a
+ * call to update()
+ * @return true if region is Dirty, false otherwise
+ *
+ * @see update();
+ */
+ public boolean isDirty();
+
+ /** Delete and clean the associated OGL
+ * objects
+ */
+ public void destroy();
+
+ public boolean isFlipped();
+
+ /** Set if the y coordinate of the region should be flipped
+ * {@code y=-y} used mainly for fonts since they use opposite vertex
+ * as origion
+ * @param flipped flag if the coordinate is flipped defaults to false.
+ */
+ public void setFlipped(boolean flipped);
+}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java b/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java
new file mode 100755
index 000000000..d3b978b8a
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.curve;
+
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLException;
+
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+import jogamp.graph.curve.opengl.VBORegionSPES2;
+import jogamp.graph.curve.opengl.VBORegion2PES2;
+
+
+/** RegionFactory to create a Context specific Region implementation.
+ *
+ * @see Region
+ */
+public class RegionFactory {
+
+ /**Create a Region based on the GLContext attached
+ * @param context the current {@link GLContext}
+ * @param st the {@link ShaderState} object
+ * @param type can be one of Region.SINGLE_PASS or Region.TWO_PASS
+ * @return region
+ */
+ public static Region create(GLContext context, ShaderState st, int type){
+ if( !context.isGL2ES2() ) {
+ throw new GLException("At least a GL2ES2 GL context is required. Given: " + context);
+ }
+ if( Region.TWO_PASS == type ){
+ return new VBORegion2PES2(context, st);
+ }
+ else{
+ return new VBORegionSPES2(context);
+ }
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
new file mode 100644
index 000000000..c1fec10b8
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java
@@ -0,0 +1,113 @@
+package com.jogamp.graph.curve.opengl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL2ES2;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.RegionFactory;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+
+public abstract class RegionRenderer extends Renderer {
+
+ /** Create a Hardware accelerated Curve Region Renderer
+ */
+ public static RegionRenderer create(Vertex.Factory<? extends Vertex> factory, int type) {
+ return new jogamp.graph.curve.opengl.RegionRendererImpl01(factory, type);
+ }
+
+ public RegionRenderer(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ /** Render an array of {@link OutlineShape}s combined in one region
+ * at the position provided the triangles of the
+ * shapes will be generated, if not yet generated
+ * @param outlineShapes array of OutlineShapes to Render.
+ * @param position the initial translation of the outlineShapes.
+ * @param texSize texture size for multipass render *
+ * @throws Exception if HwRegionRenderer not initialized
+ */
+ public abstract void renderOutlineShapes(GL2ES2 gl, OutlineShape[] outlineShapes, float[] position, int texSize);
+
+ /** Render an {@link OutlineShape} in 3D space at the position provided
+ * the triangles of the shapes will be generated, if not yet generated
+ * @param outlineShape the OutlineShape to Render.
+ * @param position the initial translation of the outlineShape.
+ * @param texSize texture size for multipass render
+ * @throws Exception if HwRegionRenderer not initialized
+ */
+ public abstract void renderOutlineShape(GL2ES2 gl, OutlineShape outlineShape, float[] position, int texSize);
+
+ protected HashMap<Integer, Region> regions = new HashMap<Integer, Region>();
+
+ public void flushCache() {
+ Iterator<Region> iterator = regions.values().iterator();
+ while(iterator.hasNext()){
+ Region region = iterator.next();
+ region.destroy();
+ }
+ regions.clear();
+ }
+
+ /** Create an ogl {@link Region} defining this {@link OutlineShape}
+ * @param sharpness parameter for Region generation
+ * @return the resulting Region.
+ */
+ protected Region createRegion(GL2ES2 gl, OutlineShape outlineShape, float sharpness) {
+ Region region = RegionFactory.create(gl.getContext(), st, renderType);
+
+ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+
+ ArrayList<Triangle> triangles = (ArrayList<Triangle>) outlineShape.triangulate(sharpness);
+ ArrayList<Vertex> vertices = (ArrayList<Vertex>) outlineShape.getVertices();
+ region.addVertices(vertices);
+ region.addTriangles(triangles);
+
+ region.update();
+ return region;
+ }
+
+ /** Create an ogl {@link Region} defining the list of {@link OutlineShape}.
+ * Combining the Shapes into single buffers.
+ * @param sharpness parameter for Region generation
+ * @return the resulting Region inclusive the generated region
+ */
+ protected Region createRegion(GL2ES2 gl, OutlineShape[] outlineShapes, float sharpness) {
+ Region region = RegionFactory.create(gl.getContext(), st, renderType);
+
+ int numVertices = region.getNumVertices();
+
+ for(OutlineShape outlineShape:outlineShapes){
+ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+
+ ArrayList<Triangle> triangles = outlineShape.triangulate(sharpness);
+ region.addTriangles(triangles);
+
+ ArrayList<Vertex> vertices = outlineShape.getVertices();
+ for(Vertex vert:vertices){
+ vert.setId(numVertices++);
+ }
+ region.addVertices(vertices);
+ }
+
+ region.update();
+ return region;
+ }
+
+ protected static int getHashCode(OutlineShape outlineShape){
+ return outlineShape.hashCode();
+ }
+
+ protected static int getHashCode(OutlineShape[] outlineShapes){
+ int hashcode = 0;
+ for(OutlineShape outlineShape:outlineShapes){
+ hashcode += getHashCode(outlineShape);
+ }
+ return hashcode;
+ }
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java
new file mode 100644
index 000000000..863928ed4
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java
@@ -0,0 +1,167 @@
+package com.jogamp.graph.curve.opengl;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import jogamp.opengl.Debug;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.opengl.SVertex;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public abstract class Renderer {
+ protected static final boolean DEBUG = Debug.debug("CurveRenderer");
+
+ protected abstract boolean initImpl(GL2ES2 gl);
+
+ protected abstract void disposeImpl(GL2ES2 gl);
+
+ /**
+ * Flushes all cached data
+ */
+ public abstract void flushCache();
+
+ public abstract float getAlpha();
+
+ public abstract void setAlpha(GL2ES2 gl, float alpha_t);
+
+ public abstract void setColor(GL2ES2 gl, float r, float g, float b);
+
+ protected final Vertex.Factory<? extends Vertex> pointFactory;
+ protected ShaderState st = new ShaderState();
+ protected PMVMatrix pmvMatrix = new PMVMatrix();
+ protected GLUniformData mgl_PMVMatrix;
+ protected int renderType;
+ protected int vp_width = 0;
+ protected int vp_height = 0;
+
+ private boolean vboSupported = false;
+ private boolean initialized = false;
+
+ /**
+ *
+ * @param factory
+ * @param renderType either {@link com.jogamp.graph.curve.Region#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#TWO_PASS}
+ */
+ protected Renderer(Vertex.Factory<? extends Vertex> factory, int renderType) {
+ this.renderType = renderType;
+ this.pointFactory = (null != factory) ? factory : SVertex.factory();
+ }
+
+ public Vertex.Factory<? extends Vertex> getFactory() { return pointFactory; }
+
+ public final boolean isInitialized() { return initialized; }
+
+ public final boolean isVBOSupported() { return vboSupported; }
+
+ public final int getRenderType() { return renderType; }
+
+ public final int getWidth() { return vp_width; }
+ public final int getHeight() { return vp_height; }
+
+ /**
+ * Initialize shaders and bindings for GPU based rendering.
+ * Leaves the renderer enabled, ie ShaderState on.
+ *
+ * @param gl the current GL state
+ * @return true if succeeded, false otherwise
+ */
+ public boolean init(GL2ES2 gl) {
+ if(initialized){
+ if(DEBUG) {
+ System.err.println("TextRenderer: Already initialized!");
+ }
+ return true;
+ }
+ vboSupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01: VBO Supported = " + isVBOSupported());
+ }
+
+ initialized = initImpl(gl);
+ return initialized;
+ }
+
+ public void dispose(GL2ES2 gl) {
+ if(!initialized){
+ if(DEBUG) {
+ System.err.println("TextRenderer: Not initialized!");
+ }
+ return;
+ }
+ disposeImpl(gl);
+ st.destroy(gl);
+ flushCache();
+ initialized = false;
+ }
+
+ public final ShaderState getShaderState() { return st; }
+
+ public final PMVMatrix getMatrix() { return pmvMatrix; }
+
+ public void rotate(GL2ES2 gl, float angle, float x, float y, float z) {
+ pmvMatrix.glRotatef(angle, x, y, z);
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public void translate(GL2ES2 gl, float x, float y, float z) {
+ pmvMatrix.glTranslatef(x, y, z);
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public void resetModelview(GL2ES2 gl) {
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public void updateMatrix(GL2ES2 gl) {
+ if(initialized && null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+ }
+
+ public boolean reshapePerspective(GL2ES2 gl, float angle, int width, int height, float near, float far) {
+ this.vp_width = width;
+ this.vp_height = height;
+ float ratio = (float)width/(float)height;
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.gluPerspective(angle, ratio, near, far);
+
+ if(initialized && null != gl) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+
+ return true;
+ }
+
+ public boolean reshapeOrtho(GL2ES2 gl, int width, int height, float near, float far) {
+ this.vp_width = width;
+ this.vp_height = height;
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glOrthof(0, width, 0, height, near, far);
+
+ if(initialized && null != gl) {
+ st.glUniform(gl, mgl_PMVMatrix);
+ }
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java
new file mode 100644
index 000000000..2bb99d27c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java
@@ -0,0 +1,103 @@
+package com.jogamp.graph.curve.opengl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL2ES2;
+
+import jogamp.graph.curve.text.GlyphString;
+import jogamp.graph.font.FontInt;
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.Vertex;
+
+public abstract class TextRenderer extends Renderer {
+
+ /**
+ * Create a Hardware accelerated Text Renderer.
+ * @param factory optional Point.Factory for Vertex construction. Default is Vertex.Factory.
+ */
+ public static TextRenderer create(Vertex.Factory<? extends Vertex> factory, int type) {
+ return new jogamp.graph.curve.opengl.TextRendererImpl01(factory, type);
+ }
+
+ protected TextRenderer(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ /** Render the String in 3D space wrt to the font provided at the position provided
+ * the outlines will be generated, if not yet generated
+ * @param gl the current GL state
+ * @param font {@link Font} to be used
+ * @param str text to be rendered
+ * @param position the lower left corner of the string
+ * @param fontSize font size
+ * @param texSize texture size for multipass render
+ * @throws Exception if TextRenderer not initialized
+ */
+ public abstract void renderString3D(GL2ES2 gl, Font font,
+ String str, float[] position, int fontSize, int texSize);
+
+ /**Create the resulting {@link GlyphString} that represents
+ * the String wrt to the font.
+ * @param font {@link Font} to be used
+ * @param size font size
+ * @param str {@link String} to be created
+ * @param sharpness parameter for Region generation of the resulting GlyphString
+ * @return the resulting GlyphString inclusive the generated region
+ */
+ protected GlyphString createString(GL2ES2 gl, Font font, int size, String str, float sharpness) {
+ AffineTransform affineTransform = new AffineTransform(pointFactory);
+
+ Path2D[] paths = new Path2D[str.length()];
+ ((FontInt)font).getOutline(str, size, affineTransform, paths);
+
+ GlyphString glyphString = new GlyphString(pointFactory, font.getName(), str);
+ glyphString.createfromFontPath(paths, affineTransform);
+ glyphString.generateRegion(gl.getContext(), sharpness, st, renderType);
+
+ return glyphString;
+ }
+
+ public void flushCache() {
+ Iterator<GlyphString> iterator = stringCacheMap.values().iterator();
+ while(iterator.hasNext()){
+ GlyphString glyphString = iterator.next();
+ glyphString.destroy();
+ }
+ stringCacheMap.clear();
+ stringCacheArray.clear();
+ }
+
+ public final void setCacheMaxSize(int newSize ) { stringCacheMaxSize = newSize; validateCache(0); }
+ public final int getCacheMaxSize() { return stringCacheMaxSize; }
+ public final int getCacheSize() { return stringCacheArray.size(); }
+
+ protected void validateCache(int space) {
+ while ( getCacheSize() + space > getCacheMaxSize() ) {
+ String key = stringCacheArray.remove(0);
+ stringCacheMap.remove(key);
+ }
+ }
+
+ protected GlyphString getCachedGlyphString(Font font, String str, int fontSize) {
+ final String key = font.getName() + "." + str.hashCode() + "." + fontSize;
+ return stringCacheMap.get(key);
+ }
+
+ protected void addCachedGlyphString(Font font, String str, int fontSize, GlyphString glyphString) {
+ final String key = font.getName() + "." + str.hashCode() + "." + fontSize;
+ validateCache(1);
+ stringCacheMap.put(key, glyphString);
+ stringCacheArray.add(stringCacheArray.size(), key);
+ }
+
+ // Cache is adding at the end of the array
+ public static final int DEFAULT_CACHE_SIZE = 32;
+ private HashMap<String, GlyphString> stringCacheMap = new HashMap<String, GlyphString>(DEFAULT_CACHE_SIZE);
+ private ArrayList<String> stringCacheArray = new ArrayList<String>(DEFAULT_CACHE_SIZE);
+ private int stringCacheMaxSize = DEFAULT_CACHE_SIZE; // -1 unlimited, 0 off, >0 limited
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java
new file mode 100644
index 000000000..a2e4ca50f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java
@@ -0,0 +1,216 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.curve.tess;
+
+import java.util.ArrayList;
+
+import jogamp.graph.curve.tess.GraphOutline;
+import jogamp.graph.curve.tess.GraphVertex;
+import jogamp.graph.curve.tess.Loop;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+import jogamp.opengl.Debug;
+
+/** Constrained Delaunay Triangulation
+ * implementation of a list of Outlines that define a set of
+ * Closed Regions with optional n holes.
+ *
+ */
+public class CDTriangulator2D {
+
+ protected static final boolean DEBUG = Debug.debug("Triangulation");
+
+ private float sharpness = 0.5f;
+ private ArrayList<Loop> loops;
+ private ArrayList<Vertex> vertices;
+
+ private ArrayList<Triangle> triangles;
+ private int maxTriID = 0;
+
+
+ public CDTriangulator2D() {
+ this(0.5f);
+ }
+
+ /** Constructor for a new Delaunay triangulator
+ * @param curveSharpness the curvature around
+ * the off-curve vertices
+ */
+ public CDTriangulator2D(float curveSharpness) {
+ this.sharpness = curveSharpness;
+ reset();
+ }
+
+ /** Reset the triangulation to initial state
+ * Clearing cached data
+ */
+ public void reset() {
+ maxTriID = 0;
+ vertices = new ArrayList<Vertex>();
+ triangles = new ArrayList<Triangle>(3);
+ loops = new ArrayList<Loop>();
+ }
+
+ /** Add a curve to the list of profiles provided
+ * @param polyline a bounding {@link Outline}
+ */
+ public void addCurve(Outline polyline){
+ Loop loop = null;
+
+ if(!loops.isEmpty()){
+ loop = getContainerLoop(polyline);
+ }
+
+ if(loop == null) {
+ GraphOutline outline = new GraphOutline(polyline);
+ GraphOutline innerPoly = extractBoundaryTriangles(outline, false);
+ vertices.addAll(polyline.getVertices());
+ loop = new Loop(innerPoly, VectorUtil.CCW);
+ loops.add(loop);
+ }
+ else {
+ GraphOutline outline = new GraphOutline(polyline);
+ GraphOutline innerPoly = extractBoundaryTriangles(outline, true);
+ vertices.addAll(innerPoly.getPoints());
+ loop.addConstraintCurve(innerPoly);
+ }
+ }
+
+ /** Generate the triangulation of the provided
+ * List of {@link Outline}s
+ */
+ public ArrayList<Triangle> generateTriangulation(){
+ for(int i=0;i<loops.size();i++) {
+ Loop loop = loops.get(i);
+ int numTries = 0;
+ int size = loop.computeLoopSize();
+ while(!loop.isSimplex()){
+ Triangle tri = null;
+ if(numTries > size){
+ tri = loop.cut(false);
+ }
+ else{
+ tri = loop.cut(true);
+ }
+ numTries++;
+
+ if(tri != null) {
+ numTries = 0;
+ size--;
+ tri.setId(maxTriID++);
+ triangles.add(tri);
+ if(DEBUG){
+ System.err.println(tri);
+ }
+ }
+ if(numTries > size*2){
+ if(DEBUG){
+ System.err.println("Triangulation not complete!");
+ }
+ break;
+ }
+ }
+ Triangle tri = loop.cut(true);
+ if(tri != null)
+ triangles.add(tri);
+ }
+ return triangles;
+ }
+
+ private GraphOutline extractBoundaryTriangles(GraphOutline outline, boolean hole){
+ GraphOutline innerOutline = new GraphOutline();
+ ArrayList<GraphVertex> outVertices = outline.getGraphPoint();
+ int size = outVertices.size();
+ for(int i=0; i < size; i++) {
+ GraphVertex currentVertex = outVertices.get(i);
+ GraphVertex gv0 = outVertices.get((i+size-1)%size);
+ GraphVertex gv2 = outVertices.get((i+1)%size);
+ GraphVertex gv1 = currentVertex;
+
+ if(!currentVertex.getPoint().isOnCurve()) {
+ Vertex v0 = gv0.getPoint().clone();
+ Vertex v2 = gv2.getPoint().clone();
+ Vertex v1 = gv1.getPoint().clone();
+
+ gv0.setBoundaryContained(true);
+ gv1.setBoundaryContained(true);
+ gv2.setBoundaryContained(true);
+
+ Triangle t= null;
+ boolean holeLike = false;
+ if(VectorUtil.ccw(v0,v1,v2)){
+ t = new Triangle(v0, v1, v2);
+ }
+ else {
+ holeLike = true;
+ t = new Triangle(v2, v1, v0);
+ }
+ t.setId(maxTriID++);
+ triangles.add(t);
+ if(DEBUG){
+ System.err.println(t);
+ }
+ if(hole || holeLike) {
+ v0.setTexCoord(0, -0.1f);
+ v2.setTexCoord(1, -0.1f);
+ v1.setTexCoord(0.5f, -1*sharpness -0.1f);
+ innerOutline.addVertex(currentVertex);
+ }
+ else {
+ v0.setTexCoord(0, 0.1f);
+ v2.setTexCoord(1, 0.1f);
+ v1.setTexCoord(0.5f, sharpness+0.1f);
+ }
+ }
+ else {
+ if(!gv2.getPoint().isOnCurve() || !gv0.getPoint().isOnCurve()){
+ currentVertex.setBoundaryContained(true);
+ }
+ innerOutline.addVertex(currentVertex);
+ }
+ }
+ return innerOutline;
+ }
+
+ private Loop getContainerLoop(Outline polyline){
+ ArrayList<Vertex> vertices = polyline.getVertices();
+ for(Vertex vert: vertices){
+ for (Loop loop:loops){
+ if(loop.checkInside(vert)){
+ return loop;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java
new file mode 100644
index 000000000..a4ab527e2
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/font/Font.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.font;
+
+import com.jogamp.graph.geom.AABBox;
+
+/**
+ * Interface wrapper for font implementation.
+ *
+ * TrueType Font Specification:
+ * http://developer.apple.com/fonts/ttrefman/rm06/Chap6.html
+ *
+ * TrueType Font Table Introduction:
+ * http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08
+ */
+
+public interface Font {
+
+ /**
+ * Metrics for font
+ *
+ * Depending on the font's direction, horizontal or vertical,
+ * the following tables shall be used:
+ *
+ * Vertical http://developer.apple.com/fonts/TTRefMan/RM06/Chap6vhea.html
+ * Horizontal http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html
+ */
+ public interface Metrics {
+ float getAscent(float pixelSize);
+ float getDescent(float pixelSize);
+ float getLineGap(float pixelSize);
+ float getMaxExtend(float pixelSize);
+ float getScale(float pixelSize);
+ AABBox getBBox(float pixelSize);
+ }
+
+ /**
+ * Glyph for font
+ */
+ public interface Glyph {
+ public Font getFont();
+ public char getSymbol();
+ public AABBox getBBox(float pixelSize);
+ public float getAdvance(float pixelSize, boolean useFrationalMetrics);
+ }
+
+
+ public String getName();
+
+ public Metrics getMetrics();
+ public Glyph getGlyph(char symbol);
+ public int getNumGlyphs();
+
+ public float getStringWidth(String string, float pixelSize);
+ public float getStringHeight(String string, float pixelSize);
+ public AABBox getStringBounds(CharSequence string, float pixelSize);
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/graph/font/FontFactory.java b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
new file mode 100644
index 000000000..1752a693c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/font/FontFactory.java
@@ -0,0 +1,80 @@
+/**
+ * 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 com.jogamp.graph.font;
+
+import java.security.AccessController;
+
+import com.jogamp.common.util.ReflectionUtil;
+
+import jogamp.graph.font.FontConstructor;
+import jogamp.graph.font.JavaFontLoader;
+import jogamp.graph.font.UbuntuFontLoader;
+import jogamp.opengl.Debug;
+
+public class FontFactory {
+ /** Ubuntu is the default font family */
+ public static final int UBUNTU = 0;
+
+ /** Java fonts are optional */
+ public static final int JAVA = 1;
+
+ private static final FontConstructor fontConstr;
+
+ static {
+ /**
+ * For example:
+ * "jogamp.graph.font.typecast.TypecastFontFactory" (default)
+ * "jogamp.graph.font.ttf.TTFFontImpl"
+ */
+ String fontImplName = Debug.getProperty("FontImpl", true, AccessController.getContext());
+ if(null == fontImplName) {
+ fontImplName = "jogamp.graph.font.typecast.TypecastFontConstructor";
+ }
+ fontConstr = (FontConstructor) ReflectionUtil.createInstance(fontImplName, FontFactory.class.getClassLoader());
+ }
+
+ public static final FontConstructor getFontConstr() { return fontConstr; }
+
+ public static final FontSet getDefault() {
+ return get(UBUNTU);
+ }
+
+ public static final FontSet get(int font) {
+ switch (font) {
+ case JAVA:
+ return JavaFontLoader.get();
+ default:
+ return UbuntuFontLoader.get();
+ }
+ }
+
+ public static final Font get(String path) {
+ return fontConstr.create(path);
+ }
+
+}
diff --git a/src/jogl/classes/com/jogamp/graph/font/FontSet.java b/src/jogl/classes/com/jogamp/graph/font/FontSet.java
new file mode 100644
index 000000000..0cee81124
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/font/FontSet.java
@@ -0,0 +1,60 @@
+/**
+ * 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 com.jogamp.graph.font;
+
+
+public interface FontSet {
+
+ /** Font family REGULAR **/
+ public static final int FAMILY_REGULAR = 0;
+
+ /** Font family LIGHT **/
+ public static final int FAMILY_LIGHT = 1;
+
+ /** Font family MEDIUM **/
+ public static final int FAMILY_MEDIUM = 2;
+
+ /** Font family CONDENSED **/
+ public static final int FAMILY_CONDENSED = 3;
+
+ /** Font family MONO **/
+ public static final int FAMILY_MONOSPACED = 4;
+
+ /** SERIF style/family bit flag. Fallback to Sans Serif. */
+ public static final int STYLE_SERIF = 1 << 1;
+
+ /** BOLD style bit flag */
+ public static final int STYLE_BOLD = 1 << 2;
+
+ /** ITALIC style bit flag */
+ public static final int STYLE_ITALIC = 1 << 3;
+
+ Font getDefault();
+
+ Font get(int family, int stylebits);
+}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/AABBox.java b/src/jogl/classes/com/jogamp/graph/geom/AABBox.java
new file mode 100644
index 000000000..8cd06329e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/geom/AABBox.java
@@ -0,0 +1,299 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.geom;
+
+import com.jogamp.graph.math.VectorUtil;
+
+/**
+ * Axis Aligned Bounding Box. Defined by two 3D coordinates (low and high)
+ * The low being the the lower left corner of the box, and the high being the upper
+ * right corner of the box.
+ *
+ */
+public class AABBox {
+ private float[] low = {Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE};
+ private float[] high = {-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE};
+ private float[] center = new float[3];
+
+ /** Create a Axis Aligned bounding box (AABBox)
+ * where the low and and high MAX float Values.
+ */
+ public AABBox() {}
+
+ /** Create an AABBox specifying the coordinates
+ * of the low and high
+ * @param lx min x-coordinate
+ * @param ly min y-coordnate
+ * @param lz min z-coordinate
+ * @param hx max x-coordinate
+ * @param hy max y-coordinate
+ * @param hz max z-coordinate
+ */
+ public AABBox(float lx, float ly, float lz,
+ float hx, float hy, float hz)
+ {
+ setLow(lx, ly, lz);
+ setHigh(hx, hy, hz);
+
+ computeCenter();
+ }
+
+ /** Create a AABBox defining the low and high
+ * @param low min xyz-coordinates
+ * @param high max xyz-coordinates
+ */
+ public AABBox(float[] low, float[] high)
+ {
+ this.low = low;
+ this.high = high;
+
+ computeCenter();
+ }
+
+ /** Get the max xyz-coordinates
+ * @return a float array containing the max xyz coordinates
+ */
+ public float[] getHigh()
+ {
+ return high;
+ }
+
+ private void setHigh(float hx, float hy, float hz)
+ {
+ this.high[0] = hx;
+ this.high[1] = hy;
+ this.high[2] = hz;
+ }
+
+ /** Get the min xyz-coordinates
+ * @return a float array containing the min xyz coordinates
+ */
+ public float[] getLow()
+ {
+ return low;
+ }
+
+ private void setLow(float lx, float ly, float lz)
+ {
+ this.low[0] = lx;
+ this.low[1] = ly;
+ this.low[2] = lz;
+ }
+
+ /** Resize the AABBox to encapsulate another AABox
+ * @param newBox AABBox to be encapsulated in
+ */
+ public void resize(AABBox newBox)
+ {
+ float[] newLow = newBox.getLow();
+ float[] newHigh = newBox.getHigh();
+
+ /** test low */
+ if (newLow[0] < low[0])
+ low[0] = newLow[0];
+ if (newLow[1] < low[1])
+ low[1] = newLow[1];
+ if (newLow[2] < low[2])
+ low[2] = newLow[2];
+
+ /** test high */
+ if (newHigh[0] > high[0])
+ high[0] = newHigh[0];
+ if (newHigh[1] > high[1])
+ high[1] = newHigh[1];
+ if (newHigh[2] > high[2])
+ high[2] = newHigh[2];
+
+ computeCenter();
+ }
+
+ private void computeCenter()
+ {
+ center[0] = (high[0] + low[0])/2;
+ center[1] = (high[1] + low[1])/2;
+ center[2] = (high[2] + low[2])/2;
+ }
+
+ /** Resize the AABBox to encapsulate the passed
+ * xyz-coordinates.
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @param z z-axis coordinate value
+ */
+ public void resize(float x, float y, float z)
+ {
+ /** test low */
+ if (x < low[0])
+ low[0] = x;
+ if (y < low[1])
+ low[1] = y;
+ if (z < low[2])
+ low[2] = z;
+
+ /** test high */
+ if (x > high[0])
+ high[0] = x;
+ if (y > high[1])
+ high[1] = y;
+ if (z > high[2])
+ high[2] = z;
+
+ computeCenter();
+ }
+
+ /** Check if the x & y coordinates are bounded/contained
+ * by this AABBox
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @return true if x belong to (low.x, high.x) and
+ * y belong to (low.y, high.y)
+ */
+ public boolean contains(float x, float y){
+ if(x<low[0] || x>high[0]){
+ return false;
+ }
+ if(y<low[1]|| y>high[1]){
+ return false;
+ }
+ return true;
+ }
+
+ /** Check if the xyz coordinates are bounded/contained
+ * by this AABBox.
+ * @param x x-axis coordinate value
+ * @param y y-axis coordinate value
+ * @param z z-axis coordinate value
+ * @return true if x belong to (low.x, high.x) and
+ * y belong to (low.y, high.y) and z belong to (low.z, high.z)
+ */
+ public boolean contains(float x, float y, float z){
+ if(x<low[0] || x>high[0]){
+ return false;
+ }
+ if(y<low[1]|| y>high[1]){
+ return false;
+ }
+ if(z<low[2] || z>high[2]){
+ return false;
+ }
+ return true;
+ }
+
+ /** Check if there is a common region between this AABBox and the passed
+ * 2D region irrespective of z range
+ * @param x lower left x-coord
+ * @param y lower left y-coord
+ * @param w width
+ * @param h hight
+ * @return true if this AABBox might have a common region with this 2D region
+ */
+ public boolean intersects(float x, float y, float w, float h) {
+ if (w <= 0 || h <= 0) {
+ return false;
+ }
+
+ final float _w = getWidth();
+ final float _h = getHeight();
+ if (_w <= 0 || _h <= 0) {
+ return false;
+ }
+
+ final float x0 = getMinX();
+ final float y0 = getMinY();
+ return (x + w > x0 &&
+ y + h > y0 &&
+ x < x0 + _w &&
+ y < y0 + _h);
+ }
+
+
+ /** Get the size of the Box where the size is represented by the
+ * length of the vector between low and high.
+ * @return a float representing the size of the AABBox
+ */
+ public float getSize(){
+ return VectorUtil.computeLength(low, high);
+ }
+
+ /**Get the Center of the AABBox
+ * @return the xyz-coordinates of the center of the AABBox
+ */
+ public float[] getCenter() {
+ return center;
+ }
+
+ /** Scale the AABBox by a constant
+ * @param size a constant float value
+ */
+ public void scale(float size) {
+ float[] diffH = new float[3];
+ diffH[0] = high[0] - center[0];
+ diffH[1] = high[1] - center[1];
+ diffH[2] = high[2] - center[2];
+
+ diffH = VectorUtil.scale(diffH, size);
+
+ float[] diffL = new float[3];
+ diffL[0] = low[0] - center[0];
+ diffL[1] = low[1] - center[1];
+ diffL[2] = low[2] - center[2];
+
+ diffL = VectorUtil.scale(diffL, size);
+
+ high = VectorUtil.vectorAdd(center, diffH);
+ low = VectorUtil.vectorAdd(center, diffL);
+ }
+
+ public float getMinX() {
+ return low[0];
+ }
+
+ public float getMinY() {
+ return low[1];
+ }
+
+ public float getWidth(){
+ return high[0] - low[0];
+ }
+
+ public float getHeight() {
+ return high[1] - low[1];
+ }
+
+ public float getDepth() {
+ return high[2] - low[2];
+ }
+ public AABBox clone(){
+ return new AABBox(this.low, this.high);
+ }
+
+ public String toString() {
+ return "[ "+low[0]+"/"+low[1]+"/"+low[1]+" .. "+high[0]+"/"+high[0]+"/"+high[0]+", ctr "+
+ center[0]+"/"+center[1]+"/"+center[1]+" ]";
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
new file mode 100644
index 000000000..a805adf6c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java
@@ -0,0 +1,176 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.geom;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+
+
+/** Define a single continuous stroke by control vertices.
+ * The vertices define the shape of the region defined by this
+ * outline. The Outline can contain a list of off-curve and on-curve
+ * vertices which define curved regions.
+ *
+ * Note: An outline should be closed to be rendered as a region.
+ *
+ * @see OutlineShape, Region
+ */
+public class Outline implements Comparable<Outline> {
+
+ private ArrayList<Vertex> vertices = new ArrayList<Vertex>(3);
+ private boolean closed = false;
+ private AABBox box = new AABBox();
+
+ /**Create an outline defined by control vertices.
+ * An outline can contain off Curve vertices which define curved
+ * regions in the outline.
+ */
+ public Outline(){
+
+ }
+
+ /** Add a vertex to the outline. The {@link Vertex} is added at the
+ * end of the outline loop/strip.
+ * @param vertex Vertex to be added
+ */
+ public final void addVertex(Vertex vertex) {
+ vertices.add(vertex);
+ box.resize(vertex.getX(), vertex.getY(), vertex.getZ());
+ }
+
+ /** Add a {@link Vertex} by specifying its 2D attributes to the outline.
+ * The {@link Vertex} is added at the
+ * end of the outline loop/strip.
+ * @param factory a {@link Factory} to get the required Vertex impl
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, boolean onCurve) {
+ addVertex(factory, x, y, 0f, onCurve);
+ }
+
+ /** Add a {@link Vertex} by specifying its 3D attributes to the outline.
+ * The {@link Vertex} is added at the
+ * end of the outline loop/strip.
+ * @param factory a {@link Factory} to get the required Vertex impl
+ * @param x the x coordinate
+ * @param y the y coordinate
+ * @param z the z coordinate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, float z, boolean onCurve) {
+ Vertex v = factory.create(x, y, z);
+ v.setOnCurve(onCurve);
+ addVertex(v);
+ }
+
+ /** Add a vertex to the outline by passing a float array and specifying the
+ * offset and length in which. The attributes of the vertex are located.
+ * The attributes should be continuous (stride = 0).
+ * Attributes which value are not set (when length less than 3)
+ * are set implicitly to zero.
+ * @param factory a {@link Factory} to get the required Vertex impl
+ * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
+ * @param offset the offset in the buffer to the x coordinate
+ * @param length the number of attributes to pick from the buffer (maximum 3)
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(Vertex.Factory<? extends Vertex> factory, float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ Vertex v = factory.create(coordsBuffer, offset, length);
+ v.setOnCurve(onCurve);
+ addVertex(v);
+ }
+
+ public Vertex getVertex(int index){
+ return vertices.get(index);
+ }
+
+ public boolean isEmpty(){
+ return (vertices.size() == 0);
+ }
+ public Vertex getLastVertex(){
+ if(isEmpty()){
+ return null;
+ }
+ return vertices.get(vertices.size()-1);
+ }
+
+ public ArrayList<Vertex> getVertices() {
+ return vertices;
+ }
+ public void setVertices(ArrayList<Vertex> vertices) {
+ this.vertices = vertices;
+ }
+ public AABBox getBox() {
+ return box;
+ }
+ public boolean isClosed() {
+ return closed;
+ }
+
+ /** define if this outline is closed or not.
+ * if set to closed, checks if the last vertex is
+ * equal to the first vertex. If not Equal adds a
+ * vertex at the end to the list.
+ * @param closed
+ */
+ public void setClosed(boolean closed) {
+ this.closed = closed;
+ if(closed){
+ Vertex first = vertices.get(0);
+ Vertex last = getLastVertex();
+ if(!VectorUtil.checkEquality(first.getCoord(), last.getCoord())){
+ Vertex v = first.clone();
+ vertices.add(v);
+ }
+ }
+ }
+
+ /** Compare two outlines with Bounding Box area
+ * as criteria.
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Outline outline) {
+ float size = box.getSize();
+ float newSize = outline.getBox().getSize();
+ if(size < newSize){
+ return -1;
+ }
+ else if(size > newSize){
+ return 1;
+ }
+ return 0;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java
new file mode 100644
index 000000000..d13e8ddb1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.geom;
+
+public class Triangle {
+ private int id = Integer.MAX_VALUE;
+ final private Vertex[] vertices;
+ private boolean[] boundaryEdges = new boolean[3];
+ private boolean[] boundaryVertices = null;
+
+ public Triangle(Vertex ... v123){
+ vertices = v123;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public Vertex[] getVertices() {
+ return vertices;
+ }
+
+ public boolean isEdgesBoundary() {
+ return boundaryEdges[0] || boundaryEdges[1] || boundaryEdges[2];
+ }
+
+ public boolean isVerticesBoundary() {
+ return boundaryVertices[0] || boundaryVertices[1] || boundaryVertices[2];
+ }
+
+ public void setEdgesBoundary(boolean[] boundary) {
+ this.boundaryEdges = boundary;
+ }
+
+ public boolean[] getEdgeBoundary() {
+ return boundaryEdges;
+ }
+
+ public boolean[] getVerticesBoundary() {
+ return boundaryVertices;
+ }
+
+ public void setVerticesBoundary(boolean[] boundaryVertices) {
+ this.boundaryVertices = boundaryVertices;
+ }
+
+ public String toString() {
+ return "Tri ID: " + id + "\n" + vertices[0] + "\n" + vertices[1] + "\n" + vertices[2];
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java
new file mode 100644
index 000000000..0e4e5e8df
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java
@@ -0,0 +1,80 @@
+/**
+ * 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 com.jogamp.graph.geom;
+
+/**
+ * A Vertex with custom memory layout using custom factory.
+ */
+public interface Vertex extends Comparable<Vertex>, Cloneable {
+
+ public static interface Factory <T extends Vertex> {
+ T create();
+
+ T create(float x, float y);
+
+ T create(float x, float y, float z);
+
+ T create(float[] coordsBuffer, int offset, int length);
+ }
+
+ void setCoord(float x, float y);
+
+ void setCoord(float x, float y, float z);
+
+ void setCoord(float[] coordsBuffer, int offset, int length);
+
+ float[] getCoord();
+
+ void setX(float x);
+
+ void setY(float y);
+
+ void setZ(float z);
+
+ float getX();
+
+ float getY();
+
+ float getZ();
+
+ boolean isOnCurve();
+
+ void setOnCurve(boolean onCurve);
+
+ int getId();
+
+ void setId(int id);
+
+ int compareTo(Vertex p);
+
+ float[] getTexCoord();
+
+ void setTexCoord(float s, float t);
+
+ Vertex clone();
+}
diff --git a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java
new file mode 100644
index 000000000..681067e40
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.geom.opengl;
+
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+/** A Simple Vertex Implementation. Where the coordinates, and other attributes are
+ * float based, and the coordinates and texture coordinates are saved in two float arrays.
+ *
+ */
+public class SVertex implements Vertex {
+ private int id = Integer.MAX_VALUE;
+ protected float[] coord = new float[3];
+ protected boolean onCurve = true;
+ private float[] texCoord = new float[2];
+
+ static final Factory factory = new Factory();
+
+ public static Factory factory() { return factory; }
+
+ public static class Factory implements Vertex.Factory<SVertex> {
+ @Override
+ public SVertex create() {
+ return new SVertex();
+ }
+
+ @Override
+ public SVertex create(float x, float y) {
+ return new SVertex(x, y);
+ }
+
+ @Override
+ public SVertex create(float x, float y, float z) {
+ return new SVertex(x, y, z);
+ }
+
+ @Override
+ public SVertex create(float[] coordsBuffer, int offset, int length) {
+ return new SVertex(coordsBuffer, offset, length);
+ }
+ }
+
+ public SVertex() {
+ }
+
+ public SVertex(float x, float y) {
+ setCoord(x, y);
+ }
+ public SVertex(float x, float y, float z) {
+ setCoord(x, y, z);
+ }
+ public SVertex(float[] coordsBuffer, int offset, int length) {
+ setCoord(coordsBuffer, offset, length);
+ }
+
+ public void setCoord(float x, float y) {
+ this.coord[0] = x;
+ this.coord[1] = y;
+ this.coord[2] = 0f;
+ }
+
+ public void setCoord(float x, float y, float z) {
+ this.coord[0] = x;
+ this.coord[1] = y;
+ this.coord[2] = z;
+ }
+
+ public void setCoord(float[] coordsBuffer, int offset, int length) {
+ if(length > coordsBuffer.length - offset) {
+ throw new IndexOutOfBoundsException("coordsBuffer too small: "+coordsBuffer.length+" - "+offset+" < "+length);
+ }
+ if(length > 3) {
+ throw new IndexOutOfBoundsException("length too big: "+length+" > "+3);
+ }
+ int i=0;
+ while(i<length) {
+ this.coord[i++] = coordsBuffer[offset++];
+ }
+ }
+
+ public float[] getCoord() {
+ return coord;
+ }
+
+ public void setX(float x) {
+ this.coord[0] = x;
+ }
+
+ public void setY(float y) {
+ this.coord[1] = y;
+ }
+
+ public void setZ(float z) {
+ this.coord[2] = z;
+ }
+
+ public float getX() {
+ return this.coord[0];
+ }
+
+ public float getY() {
+ return this.coord[1];
+ }
+
+ public float getZ() {
+ return this.coord[2];
+ }
+
+ public boolean isOnCurve() {
+ return onCurve;
+ }
+
+ public void setOnCurve(boolean onCurve) {
+ this.onCurve = onCurve;
+ }
+
+ public int getId(){
+ return id;
+ }
+
+ public void setId(int id){
+ this.id = id;
+ }
+
+ public int compareTo(Vertex p) {
+ if(VectorUtil.checkEquality(coord, p.getCoord())) {
+ return 0;
+ }
+ return -1;
+ }
+
+ public float[] getTexCoord() {
+ return texCoord;
+ }
+
+ public void setTexCoord(float s, float t) {
+ this.texCoord[0] = s;
+ this.texCoord[1] = t;
+ }
+
+ public SVertex clone(){
+ SVertex v = new SVertex(this.coord, 0, 3);
+ v.setOnCurve(this.onCurve);
+ return v;
+ }
+
+ public String toString() {
+ return "[ID: " + id + " X: " + coord[0]
+ + " Y: " + coord[1] + " Z: " + coord[2] + "]";
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/math/Quaternion.java b/src/jogl/classes/com/jogamp/graph/math/Quaternion.java
new file mode 100755
index 000000000..b77a5fa08
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/math/Quaternion.java
@@ -0,0 +1,382 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.math;
+
+import jogamp.graph.math.MathFloat;
+
+public class Quaternion {
+ protected float x,y,z,w;
+
+ public Quaternion(){
+
+ }
+
+ public Quaternion(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /** Constructor to create a rotation based quaternion from two vectors
+ * @param vector1
+ * @param vector2
+ */
+ public Quaternion(float[] vector1, float[] vector2)
+ {
+ float theta = (float)MathFloat.acos(dot(vector1, vector2));
+ float[] cross = cross(vector1,vector2);
+ cross = normalizeVec(cross);
+
+ this.x = (float)MathFloat.sin(theta/2)*cross[0];
+ this.y = (float)MathFloat.sin(theta/2)*cross[1];
+ this.z = (float)MathFloat.sin(theta/2)*cross[2];
+ this.w = (float)MathFloat.cos(theta/2);
+ this.normalize();
+ }
+
+ /** Transform the rotational quaternion to axis based rotation angles
+ * @return new float[4] with ,theta,Rx,Ry,Rz
+ */
+ public float[] toAxis()
+ {
+ float[] vec = new float[4];
+ float scale = (float)MathFloat.sqrt(x * x + y * y + z * z);
+ vec[0] =(float) MathFloat.acos(w) * 2.0f;
+ vec[1] = x / scale;
+ vec[2] = y / scale;
+ vec[3] = z / scale;
+ return vec;
+ }
+
+ /** Normalize a vector
+ * @param vector input vector
+ * @return normalized vector
+ */
+ private float[] normalizeVec(float[] vector)
+ {
+ float[] newVector = new float[3];
+
+ float d = MathFloat.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
+ if(d> 0.0f)
+ {
+ newVector[0] = vector[0]/d;
+ newVector[1] = vector[1]/d;
+ newVector[2] = vector[2]/d;
+ }
+ return newVector;
+ }
+ /** compute the dot product of two points
+ * @param vec1 vector 1
+ * @param vec2 vector 2
+ * @return the dot product as float
+ */
+ private float dot(float[] vec1, float[] vec2)
+ {
+ return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
+ }
+ /** cross product vec1 x vec2
+ * @param vec1 vector 1
+ * @param vec2 vecttor 2
+ * @return the resulting vector
+ */
+ private float[] cross(float[] vec1, float[] vec2)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec2[2]*vec1[1] - vec2[1]*vec1[2];
+ out[1] = vec2[0]*vec1[2] - vec2[2]*vec1[0];
+ out[2] = vec2[1]*vec1[0] - vec2[0]*vec1[1];
+
+ return out;
+ }
+ public float getW() {
+ return w;
+ }
+ public void setW(float w) {
+ this.w = w;
+ }
+ public float getX() {
+ return x;
+ }
+ public void setX(float x) {
+ this.x = x;
+ }
+ public float getY() {
+ return y;
+ }
+ public void setY(float y) {
+ this.y = y;
+ }
+ public float getZ() {
+ return z;
+ }
+ public void setZ(float z) {
+ this.z = z;
+ }
+
+ /** Add a quaternion
+ * @param q quaternion
+ */
+ public void add(Quaternion q)
+ {
+ x+=q.x;
+ y+=q.y;
+ z+=q.z;
+ }
+
+ /** Subtract a quaternion
+ * @param q quaternion
+ */
+ public void subtract(Quaternion q)
+ {
+ x-=q.x;
+ y-=q.y;
+ z-=q.z;
+ }
+
+ /** Divide a quaternion by a constant
+ * @param n a float to divide by
+ */
+ public void divide(float n)
+ {
+ x/=n;
+ y/=n;
+ z/=n;
+ }
+
+ /** Multiply this quaternion by
+ * the param quaternion
+ * @param q a quaternion to multiply with
+ */
+ public void mult(Quaternion q)
+ {
+ float w1 = w*q.w - (x*q.x + y*q.y + z*q.z);
+
+ float x1 = w*q.z + q.w*z + y*q.z - z*q.y;
+ float y1 = w*q.x + q.w*x + z*q.x - x*q.z;
+ float z1 = w*q.y + q.w*y + x*q.y - y*q.x;
+
+ w = w1;
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ /** Multiply a quaternion by a constant
+ * @param n a float constant
+ */
+ public void mult(float n)
+ {
+ x*=n;
+ y*=n;
+ z*=n;
+ }
+
+ /** Normalize a quaternion required if
+ * to be used as a rotational quaternion
+ */
+ public void normalize()
+ {
+ float norme = (float)MathFloat.sqrt(w*w + x*x + y*y + z*z);
+ if (norme == 0.0f)
+ {
+ w = 1.0f;
+ x = y = z = 0.0f;
+ }
+ else
+ {
+ float recip = 1.0f/norme;
+
+ w *= recip;
+ x *= recip;
+ y *= recip;
+ z *= recip;
+ }
+ }
+
+ /** Invert the quaternion If rotational,
+ * will produce a the inverse rotation
+ */
+ public void inverse()
+ {
+ float norm = w*w + x*x + y*y + z*z;
+
+ float recip = 1.0f/norm;
+
+ w *= recip;
+ x = -1*x*recip;
+ y = -1*y*recip;
+ z = -1*z*recip;
+ }
+
+ /** Transform this quaternion to a
+ * 4x4 column matrix representing the rotation
+ * @return new float[16] column matrix 4x4
+ */
+ public float[] toMatrix()
+ {
+ float[] matrix = new float[16];
+ matrix[0] = 1.0f - 2*y*y - 2*z*z;
+ matrix[1] = 2*x*y + 2*w*z;
+ matrix[2] = 2*x*z - 2*w*y;
+ matrix[3] = 0;
+
+ matrix[4] = 2*x*y - 2*w*z;
+ matrix[5] = 1.0f - 2*x*x - 2*z*z;
+ matrix[6] = 2*y*z + 2*w*x;
+ matrix[7] = 0;
+
+ matrix[8] = 2*x*z + 2*w*y;
+ matrix[9] = 2*y*z - 2*w*x;
+ matrix[10] = 1.0f - 2*x*x - 2*y*y;
+ matrix[11] = 0;
+
+ matrix[12] = 0;
+ matrix[13] = 0;
+ matrix[14] = 0;
+ matrix[15] = 1;
+ return matrix;
+ }
+
+ /** Set this quaternion from a Sphereical interpolation
+ * of two param quaternion, used mostly for rotational animation
+ * @param a initial quaternion
+ * @param b target quaternion
+ * @param t float between 0 and 1 representing interp.
+ */
+ public void slerp(Quaternion a,Quaternion b, float t)
+ {
+ float omega, cosom, sinom, sclp, sclq;
+ cosom = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
+ if ((1.0f+cosom) > MathFloat.E) {
+ if ((1.0f-cosom) > MathFloat.E) {
+ omega = (float)MathFloat.acos(cosom);
+ sinom = (float)MathFloat.sin(omega);
+ sclp = (float)MathFloat.sin((1.0f-t)*omega) / sinom;
+ sclq = (float)MathFloat.sin(t*omega) / sinom;
+ }
+ else {
+ sclp = 1.0f - t;
+ sclq = t;
+ }
+ x = sclp*a.x + sclq*b.x;
+ y = sclp*a.y + sclq*b.y;
+ z = sclp*a.z + sclq*b.z;
+ w = sclp*a.w + sclq*b.w;
+ }
+ else {
+ x =-a.y;
+ y = a.x;
+ z =-a.w;
+ w = a.z;
+ sclp = MathFloat.sin((1.0f-t) * MathFloat.PI * 0.5f);
+ sclq = MathFloat.sin(t * MathFloat.PI * 0.5f);
+ x = sclp*a.x + sclq*b.x;
+ y = sclp*a.y + sclq*b.y;
+ z = sclp*a.z + sclq*b.z;
+ }
+ }
+
+ /** Check if this quaternion is empty, ie (0,0,0,1)
+ * @return true if empty, false otherwise
+ */
+ public boolean isEmpty()
+ {
+ if (w==1 && x==0 && y==0 && z==0)
+ return true;
+ return false;
+ }
+
+ /** Check if this quaternion represents an identity
+ * matrix, for rotation.
+ * @return true if it is an identity rep., false otherwise
+ */
+ public boolean isIdentity()
+ {
+ if (w==0 && x==0 && y==0 && z==0)
+ return true;
+ return false;
+ }
+
+ /** compute the quaternion from a 3x3 column matrix
+ * @param m 3x3 column matrix
+ */
+ public void setFromMatrix(float[] m) {
+ float T= m[0] + m[4] + m[8] + 1;
+ if (T>0){
+ float S = 0.5f / (float)MathFloat.sqrt(T);
+ w = 0.25f / S;
+ x = ( m[5] - m[7]) * S;
+ y = ( m[6] - m[2]) * S;
+ z = ( m[1] - m[3] ) * S;
+ }
+ else{
+ if ((m[0] > m[4])&(m[0] > m[8])) {
+ float S = MathFloat.sqrt( 1.0f + m[0] - m[4] - m[8] ) * 2f; // S=4*qx
+ w = (m[7] - m[5]) / S;
+ x = 0.25f * S;
+ y = (m[3] + m[1]) / S;
+ z = (m[6] + m[2]) / S;
+ }
+ else if (m[4] > m[8]) {
+ float S = MathFloat.sqrt( 1.0f + m[4] - m[0] - m[8] ) * 2f; // S=4*qy
+ w = (m[6] - m[2]) / S;
+ x = (m[3] + m[1]) / S;
+ y = 0.25f * S;
+ z = (m[7] + m[5]) / S;
+ }
+ else {
+ float S = MathFloat.sqrt( 1.0f + m[8] - m[0] - m[4] ) * 2f; // S=4*qz
+ w = (m[3] - m[1]) / S;
+ x = (m[6] + m[2]) / S;
+ y = (m[7] + m[5]) / S;
+ z = 0.25f * S;
+ }
+ }
+ }
+
+ /** Check if the the 3x3 matrix (param) is in fact
+ * an affine rotational matrix
+ * @param m 3x3 column matrix
+ * @return true if representing a rotational matrix, false otherwise
+ */
+ public boolean isRotationMatrix(float[] m) {
+ double epsilon = 0.01; // margin to allow for rounding errors
+ if (MathFloat.abs(m[0]*m[3] + m[3]*m[4] + m[6]*m[7]) > epsilon) return false;
+ if (MathFloat.abs(m[0]*m[2] + m[3]*m[5] + m[6]*m[8]) > epsilon) return false;
+ if (MathFloat.abs(m[1]*m[2] + m[4]*m[5] + m[7]*m[8]) > epsilon) return false;
+ if (MathFloat.abs(m[0]*m[0] + m[3]*m[3] + m[6]*m[6] - 1) > epsilon) return false;
+ if (MathFloat.abs(m[1]*m[1] + m[4]*m[4] + m[7]*m[7] - 1) > epsilon) return false;
+ if (MathFloat.abs(m[2]*m[2] + m[5]*m[5] + m[8]*m[8] - 1) > epsilon) return false;
+ return (MathFloat.abs(determinant(m)-1) < epsilon);
+ }
+ private float determinant(float[] m) {
+ return m[0]*m[4]*m[8] + m[3]*m[7]*m[2] + m[6]*m[1]*m[5] - m[0]*m[7]*m[5] - m[3]*m[1]*m[8] - m[6]*m[4]*m[2];
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java b/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java
new file mode 100755
index 000000000..cca9a454f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java
@@ -0,0 +1,295 @@
+/**
+ * Copyright 2010 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 com.jogamp.graph.math;
+
+import java.util.ArrayList;
+
+import jogamp.graph.math.MathFloat;
+
+import com.jogamp.graph.geom.Vertex;
+
+public class VectorUtil {
+
+ public static final int CW = -1;
+ public static final int CCW = 1;
+ public static final int COLLINEAR = 0;
+
+ /** compute the dot product of two points
+ * @param vec1 vector 1
+ * @param vec2 vector 2
+ * @return the dot product as float
+ */
+ public static float dot(float[] vec1, float[] vec2)
+ {
+ return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
+ }
+ /** Normalize a vector
+ * @param vector input vector
+ * @return normalized vector
+ */
+ public static float[] normalize(float[] vector)
+ {
+ float[] newVector = new float[3];
+
+ float d = MathFloat.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
+ if(d> 0.0f)
+ {
+ newVector[0] = vector[0]/d;
+ newVector[1] = vector[1]/d;
+ newVector[2] = vector[2]/d;
+ }
+ return newVector;
+ }
+
+ /** Scales a vector by param
+ * @param vector input vector
+ * @param scale constant to scale by
+ * @return scaled vector
+ */
+ public static float[] scale(float[] vector, float scale)
+ {
+ float[] newVector = new float[3];
+
+ newVector[0] = vector[0]*scale;
+ newVector[1] = vector[1]*scale;
+ newVector[2] = vector[2]*scale;
+ return newVector;
+ }
+
+ /** Adds to vectors
+ * @param v1 vector 1
+ * @param v2 vector 2
+ * @return v1 + v2
+ */
+ public static float[] vectorAdd(float[] v1, float[] v2)
+ {
+ float[] newVector = new float[3];
+
+ newVector[0] = v1[0] + v2[0];
+ newVector[1] = v1[1] + v2[1];
+ newVector[2] = v1[2] + v2[2];
+ return newVector;
+ }
+
+ /** cross product vec1 x vec2
+ * @param vec1 vector 1
+ * @param vec2 vecttor 2
+ * @return the resulting vector
+ */
+ public static float[] cross(float[] vec1, float[] vec2)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec2[2]*vec1[1] - vec2[1]*vec1[2];
+ out[1] = vec2[0]*vec1[2] - vec2[2]*vec1[0];
+ out[2] = vec2[1]*vec1[0] - vec2[0]*vec1[1];
+
+ return out;
+ }
+
+ /** Column Matrix Vector multiplication
+ * @param colMatrix column matrix (4x4)
+ * @param vec vector(x,y,z)
+ * @return result new float[3]
+ */
+ public static float[] colMatrixVectorMult(float[] colMatrix, float[] vec)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec[0]*colMatrix[0] + vec[1]*colMatrix[4] + vec[2]*colMatrix[8] + colMatrix[12];
+ out[1] = vec[0]*colMatrix[1] + vec[1]*colMatrix[5] + vec[2]*colMatrix[9] + colMatrix[13];
+ out[2] = vec[0]*colMatrix[2] + vec[1]*colMatrix[6] + vec[2]*colMatrix[10] + colMatrix[14];
+
+ return out;
+ }
+
+ /** Matrix Vector multiplication
+ * @param rawMatrix column matrix (4x4)
+ * @param vec vector(x,y,z)
+ * @return result new float[3]
+ */
+ public static float[] rowMatrixVectorMult(float[] rawMatrix, float[] vec)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec[0]*rawMatrix[0] + vec[1]*rawMatrix[1] + vec[2]*rawMatrix[2] + rawMatrix[3];
+ out[1] = vec[0]*rawMatrix[4] + vec[1]*rawMatrix[5] + vec[2]*rawMatrix[6] + rawMatrix[7];
+ out[2] = vec[0]*rawMatrix[8] + vec[1]*rawMatrix[9] + vec[2]*rawMatrix[10] + rawMatrix[11];
+
+ return out;
+ }
+
+ /** Calculate the midpoint of two values
+ * @param p1 first value
+ * @param p2 second vale
+ * @return midpoint
+ */
+ public static float mid(float p1, float p2)
+ {
+ return (p1+p2)/2.0f;
+ }
+ /** Calculate the midpoint of two points
+ * @param p1 first point
+ * @param p2 second point
+ * @return midpoint
+ */
+ public static float[] mid(float[] p1, float[] p2)
+ {
+ float[] midPoint = new float[3];
+ midPoint[0] = (p1[0] + p2[0])/2.0f;
+ midPoint[1] = (p1[1] + p2[1])/2.0f;
+ midPoint[2] = (p1[2] + p2[2])/2.0f;
+
+ return midPoint;
+ }
+ /** Compute the norm of a vector
+ * @param vec vector
+ * @return vorm
+ */
+ public static float norm(float[] vec)
+ {
+ return MathFloat.sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+ }
+ /** Compute distance between 2 points
+ * @param p0 a ref point on the line
+ * @param vec vector representing the direction of the line
+ * @param point the point to compute the relative distance of
+ * @return distance float
+ */
+ public static float computeLength(float[] p0, float[] point)
+ {
+ float[] w = new float[]{point[0]-p0[0],point[1]-p0[1],point[2]-p0[2]};
+
+ float distance = MathFloat.sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]);
+
+ return distance;
+ }
+
+ /**Check equality of 2 vec3 vectors
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @return
+ */
+ public static boolean checkEquality(float[] v1, float[] v2)
+ {
+ if(Float.compare(v1[0], v2[0]) == 0
+ && Float.compare(v1[1] , v2[1]) == 0
+ && Float.compare(v1[2], v2[2]) == 0 )
+ return true;
+ return false;
+ }
+
+ /** Compute the determinant of 3 vectors
+ * @param a vector 1
+ * @param b vector 2
+ * @param c vector 3
+ * @return the determinant value
+ */
+ public static float computeDeterminant(float[] a, float[] b, float[] c)
+ {
+ float area = a[0]*b[1]*c[2] + a[1]*b[2]*c[0] + a[2]*b[0]*c[1] - a[0]*b[2]*c[1] - a[1]*b[0]*c[2] - a[2]*b[1]*c[0];
+ return area;
+ }
+
+ /** Check if three vertices are colliniear
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @param v3 vertex 3
+ * @return true if collinear, false otherwise
+ */
+ public static boolean checkCollinear(float[] v1, float[] v2, float[] v3)
+ {
+ return (computeDeterminant(v1, v2, v3) == VectorUtil.COLLINEAR);
+ }
+
+ /** Compute Vector
+ * @param v1 vertex 1
+ * @param v2 vertex2 2
+ * @return Vector V1V2
+ */
+ public static float[] computeVector(float[] v1, float[] v2)
+ {
+ float[] vector = new float[3];
+ vector[0] = v2[0] - v1[0];
+ vector[1] = v2[1] - v1[1];
+ vector[2] = v2[2] - v1[2];
+ return vector;
+ }
+
+ /** Check if vertices in triangle circumcircle
+ * @param a triangle vertex 1
+ * @param b triangle vertex 2
+ * @param c triangle vertex 3
+ * @param d vertex in question
+ * @return true if the vertex d is inside the circle defined by the
+ * vertices a, b, c. from paper by Guibas and Stolfi (1985).
+ */
+ public static boolean inCircle(Vertex a, Vertex b, Vertex c, Vertex d){
+ return (a.getX() * a.getX() + a.getY() * a.getY()) * triArea(b, c, d) -
+ (b.getX() * b.getX() + b.getY() * b.getY()) * triArea(a, c, d) +
+ (c.getX() * c.getX() + c.getY() * c.getY()) * triArea(a, b, d) -
+ (d.getX() * d.getX() + d.getY() * d.getY()) * triArea(a, b, c) > 0;
+ }
+
+ /** Computes oriented area of a triangle
+ * @param a first vertex
+ * @param b second vertex
+ * @param c third vertex
+ * @return compute twice the area of the oriented triangle (a,b,c), the area
+ * is positive if the triangle is oriented counterclockwise.
+ */
+ public static float triArea(Vertex a, Vertex b, Vertex c){
+ return (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY())*(c.getX() - a.getX());
+ }
+
+ /** Check if points are in ccw order
+ * @param a first vertex
+ * @param b second vertex
+ * @param c third vertex
+ * @return true if the points a,b,c are in a ccw order
+ */
+ public static boolean ccw(Vertex a, Vertex b, Vertex c){
+ return triArea(a,b,c) > 0;
+ }
+
+ /** Computes the area of a list of vertices to check if ccw
+ * @param vertices
+ * @return positve area if ccw else negative area value
+ */
+ public static float area(ArrayList<Vertex> vertices) {
+ int n = vertices.size();
+ float area = 0.0f;
+ for (int p = n - 1, q = 0; q < n; p = q++)
+ {
+ float[] pCoord = vertices.get(p).getCoord();
+ float[] qCoord = vertices.get(q).getCoord();
+ area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1];
+ }
+ return area;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/RegionRendererImpl01.java b/src/jogl/classes/jogamp/graph/curve/opengl/RegionRendererImpl01.java
new file mode 100755
index 000000000..c1f293fff
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/opengl/RegionRendererImpl01.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright 2010 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.curve.opengl;
+
+import java.nio.FloatBuffer;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+
+public class RegionRendererImpl01 extends RegionRenderer {
+ /**Sharpness is equivalent to the value of t value of texture coord
+ * on the off-curve vertex. The high value of sharpness will
+ * result in high curvature.
+ */
+ private GLUniformData mgl_sharpness = new GLUniformData("p1y", 0.5f);
+ GLUniformData mgl_alpha = new GLUniformData("g_alpha", 1.0f);
+ private GLUniformData mgl_color = new GLUniformData("g_color", 3, FloatBuffer.allocate(3));
+ private GLUniformData mgl_strength = new GLUniformData("a_strength", 3.0f);
+
+ public RegionRendererImpl01(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ protected boolean initImpl(GL2ES2 gl) {
+ boolean VBOsupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("RegionRenderer: VBO Supported = " + VBOsupported);
+ }
+
+ if(!VBOsupported){
+ return false;
+ }
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
+
+ ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, RegionRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+ ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, RegionRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+
+ ShaderProgram sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if(!sp.link(gl, System.err)) {
+ throw new GLException("RegionRenderer: Couldn't link program: "+sp);
+ }
+
+ st = new ShaderState();
+ st.attachShaderProgram(gl, sp);
+ gl.glBindAttribLocation(sp.id(), 0, "v_position");
+ gl.glBindAttribLocation(sp.id(), 1, "texCoord");
+
+ st.glUseProgram(gl, true);
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ resetModelview(null);
+
+ mgl_PMVMatrix = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
+ if(!st.glUniform(gl, mgl_PMVMatrix)) {
+ if(DEBUG){
+ System.err.println("Error setting PMVMatrix in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_sharpness)) {
+ if(DEBUG){
+ System.err.println("Error setting sharpness in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_alpha)) {
+ if(DEBUG){
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_color)) {
+ if(DEBUG){
+ System.err.println("Error setting global color in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_strength)) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+
+ if(DEBUG) {
+ System.err.println("RegionRendererImpl01 initialized: " + Thread.currentThread()+" "+st);
+ }
+ return true;
+ }
+
+ @Override
+ protected void disposeImpl(GL2ES2 gl) {
+ }
+
+
+ @Override
+ public float getAlpha() {
+ return mgl_alpha.floatValue();
+ }
+
+ @Override
+ public void setAlpha(GL2ES2 gl, float alpha_t) {
+ mgl_alpha.setData(alpha_t);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_alpha);
+ }
+ }
+
+ @Override
+ public void setColor(GL2ES2 gl, float r, float g, float b){
+ FloatBuffer fb = (FloatBuffer) mgl_color.getBuffer();
+ fb.put(0, r);
+ fb.put(1, r);
+ fb.put(2, r);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_color);
+ }
+ }
+
+
+ @Override
+ public void renderOutlineShape(GL2ES2 gl, OutlineShape outlineShape, float[] position, int texSize) {
+ if(!isInitialized()){
+ throw new GLException("RegionRendererImpl01: not initialized!");
+ }
+ int hashCode = getHashCode(outlineShape);
+ Region region = regions.get(hashCode);
+
+ if(null == region) {
+ region = createRegion(gl, outlineShape, mgl_sharpness.floatValue());
+ regions.put(hashCode, region);
+ }
+ region.render(pmvMatrix, vp_width, vp_height, texSize);
+ }
+
+ @Override
+ public void renderOutlineShapes(GL2ES2 gl, OutlineShape[] outlineShapes, float[] position, int texSize) {
+ if(!isInitialized()){
+ throw new GLException("RegionRendererImpl01: not initialized!");
+ }
+
+ int hashCode = getHashCode(outlineShapes);
+ Region region = regions.get(hashCode);
+
+ if(null == region) {
+ region = createRegion(gl, outlineShapes, mgl_sharpness.floatValue());
+ regions.put(hashCode, region);
+ }
+ region.render(pmvMatrix, vp_width, vp_height, texSize);
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java b/src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java
new file mode 100644
index 000000000..cebe7a19e
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/opengl/TextRendererImpl01.java
@@ -0,0 +1,188 @@
+/**
+ * Copyright 2010 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.curve.opengl;
+
+import java.nio.FloatBuffer;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import jogamp.graph.curve.text.GlyphString;
+
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
+
+public class TextRendererImpl01 extends TextRenderer {
+ /**Sharpness is equivalent to the value of t value of texture coord
+ * on the off-curve vertex. The high value of sharpness will
+ * result in high curvature.
+ */
+ private GLUniformData mgl_sharpness = new GLUniformData("p1y", 0.5f);
+ GLUniformData mgl_alpha = new GLUniformData("g_alpha", 1.0f);
+ private GLUniformData mgl_color = new GLUniformData("g_color", 3, FloatBuffer.allocate(3));
+ private GLUniformData mgl_strength = new GLUniformData("a_strength", 1.8f);
+
+ public TextRendererImpl01(Vertex.Factory<? extends Vertex> factory, int type) {
+ super(factory, type);
+ }
+
+ @Override
+ protected boolean initImpl(GL2ES2 gl){
+ boolean VBOsupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01: VBO Supported = " + VBOsupported);
+ }
+
+ if(!VBOsupported){
+ return false;
+ }
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
+
+ ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, TextRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+ ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, TextRendererImpl01.class,
+ "shader", "shader/bin", "curverenderer01");
+
+ ShaderProgram sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if(!sp.link(gl, System.err)) {
+ throw new GLException("TextRendererImpl01: Couldn't link program: "+sp);
+ }
+
+ st.attachShaderProgram(gl, sp);
+ gl.glBindAttribLocation(sp.id(), 0, "v_position");
+ gl.glBindAttribLocation(sp.id(), 1, "texCoord");
+
+ st.glUseProgram(gl, true);
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ resetModelview(null);
+
+ mgl_PMVMatrix = new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf());
+ if(!st.glUniform(gl, mgl_PMVMatrix)) {
+ if(DEBUG){
+ System.err.println("Error setting PMVMatrix in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_sharpness)) {
+ if(DEBUG){
+ System.err.println("Error setting sharpness in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_alpha)) {
+ if(DEBUG){
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_color)) {
+ if(DEBUG){
+ System.err.println("Error setting global color in shader: "+st);
+ }
+ return false;
+ }
+
+ if(!st.glUniform(gl, mgl_strength)) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+
+ if(DEBUG) {
+ System.err.println("TextRendererImpl01 initialized: " + Thread.currentThread()+" "+st);
+ }
+ return true;
+ }
+
+ @Override
+ protected void disposeImpl(GL2ES2 gl) {
+ }
+
+ @Override
+ public float getAlpha() {
+ return mgl_alpha.floatValue();
+ }
+
+ @Override
+ public void setAlpha(GL2ES2 gl, float alpha_t) {
+ mgl_alpha.setData(alpha_t);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_alpha);
+ }
+ }
+
+ @Override
+ public void setColor(GL2ES2 gl, float r, float g, float b){
+ FloatBuffer fb = (FloatBuffer) mgl_color.getBuffer();
+ fb.put(0, r);
+ fb.put(1, r);
+ fb.put(2, r);
+ if(null != gl && st.inUse()) {
+ st.glUniform(gl, mgl_color);
+ }
+ }
+
+ @Override
+ public void renderString3D(GL2ES2 gl, Font font, String str, float[] position, int fontSize, int texSize) {
+ if(!isInitialized()){
+ throw new GLException("TextRendererImpl01: not initialized!");
+ }
+ GlyphString glyphString = getCachedGlyphString(font, str, fontSize);
+ if(null == glyphString) {
+ glyphString = createString(gl, font, fontSize, str, mgl_sharpness.floatValue());
+ addCachedGlyphString(font, str, fontSize, glyphString);
+ }
+
+ glyphString.renderString3D(pmvMatrix, vp_width, vp_height, texSize);
+ }
+
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PES2.java b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PES2.java
new file mode 100644
index 000000000..c7c370f6d
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegion2PES2.java
@@ -0,0 +1,385 @@
+/**
+ * Copyright 2010 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.curve.opengl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+
+import javax.media.opengl.GL2ES2;
+// FIXME: Subsume GL2GL3.GL_DRAW_FRAMEBUFFER -> GL2ES2.GL_DRAW_FRAMEBUFFER !
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import com.jogamp.common.nio.Buffers;
+
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public class VBORegion2PES2 implements Region{
+ private int numVertices = 0;
+ private IntBuffer vboIds;
+
+ private IntBuffer t_vboIds;
+
+ private ArrayList<Triangle> triangles = new ArrayList<Triangle>();
+ private ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+ private GLContext context;
+
+ private int numBuffers = 3;
+
+ private boolean flipped = false;
+
+ private boolean dirty = false;
+
+ private AABBox box = null;
+ private int[] texture = { 0 } ;
+ private int[] fbo = { 0 } ;
+ private int[] rbo_depth = { 0 } ;
+ private boolean texInitialized = false;
+
+ private int tex_width_c = 0;
+ private int tex_height_c = 0;
+
+ private ShaderState st;
+
+ public VBORegion2PES2(GLContext context, ShaderState st){
+ this.context =context;
+ this.st = st;
+ }
+
+ public void update(){
+ box = new AABBox();
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ ShortBuffer indicies = Buffers.newDirectShortBuffer(triangles.size() * 3);
+
+ for(Triangle t:triangles){
+ if(t.getVertices()[0].getId() == Integer.MAX_VALUE){
+ t.getVertices()[0].setId(numVertices++);
+ t.getVertices()[1].setId(numVertices++);
+ t.getVertices()[2].setId(numVertices++);
+
+ vertices.add(t.getVertices()[0]);
+ vertices.add(t.getVertices()[1]);
+ vertices.add(t.getVertices()[2]);
+
+ indicies.put((short) t.getVertices()[0].getId());
+ indicies.put((short) t.getVertices()[1].getId());
+ indicies.put((short) t.getVertices()[2].getId());
+ }
+ else{
+ Vertex v1 = t.getVertices()[0];
+ Vertex v2 = t.getVertices()[1];
+ Vertex v3 = t.getVertices()[2];
+
+ indicies.put((short) v1.getId());
+ indicies.put((short) v2.getId());
+ indicies.put((short) v3.getId());
+ }
+ }
+ indicies.rewind();
+
+ FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 3);
+ for(Vertex v:vertices){
+ verticesBuffer.put(v.getX());
+ if(flipped){
+ verticesBuffer.put(-1*v.getY());
+ }
+ else{
+ verticesBuffer.put(v.getY());
+ }
+ verticesBuffer.put(v.getZ());
+ if(flipped){
+ box.resize(v.getX(), -1*v.getY(), v.getZ());
+ }
+ else{
+ box.resize(v.getX(), v.getY(), v.getZ());
+ }
+ }
+ verticesBuffer.rewind();
+
+ FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 2);
+ for(Vertex v:vertices){
+ float[] tex = v.getTexCoord();
+ texCoordBuffer.put(tex[0]);
+ texCoordBuffer.put(tex[1]);
+ }
+ texCoordBuffer.rewind();
+
+ vboIds = IntBuffer.allocate(numBuffers);
+ gl.glGenBuffers(numBuffers, vboIds);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0)); // vertices
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1)); //texture
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); //triangles
+ gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, triangles.size()* 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dirty = false;
+ }
+
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width){
+ if(null == matrix || vp_width <=0 || vp_height <= 0 || width <= 0){
+ renderRegion();
+ }
+ else {
+ if(width != tex_width_c){
+ texInitialized = false;
+ tex_width_c = width;
+ }
+ if(!texInitialized){
+ initFBOTexture(matrix,vp_width, vp_height);
+ texInitialized = true;
+ }
+// System.out.println("Scale: " + matrix.glGetMatrixf().get(1+4*3) +" " + matrix.glGetMatrixf().get(2+4*3));
+ renderTexture(matrix, vp_width, vp_height);
+ }
+ }
+
+ private void renderTexture(PMVMatrix matrix, int width, int hight){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ gl.glViewport(0, 0, width, hight);
+ if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, matrix.glGetPMvMatrixf()))){
+ System.out.println("Cnt set tex based mat");
+ }
+ gl.glEnable(GL2ES2.GL_TEXTURE_2D);
+ gl.glActiveTexture(GL2ES2.GL_TEXTURE0);
+ gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, texture[0]);
+
+ st.glUniform(gl, new GLUniformData("texture", texture[0]));
+ int loc = gl.glGetUniformLocation(st.shaderProgram().id(), "texture");
+ gl.glUniform1i(loc, 0);
+
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(0));
+ gl.glEnableVertexAttribArray(VERTEX_ATTR_IDX);
+ gl.glVertexAttribPointer(VERTEX_ATTR_IDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(1));
+ gl.glEnableVertexAttribArray(TEXCOORD_ATTR_IDX);
+ gl.glVertexAttribPointer(TEXCOORD_ATTR_IDX, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, t_vboIds.get(2));
+ gl.glDrawElements(GL2ES2.GL_TRIANGLES, 2 * 3, GL2ES2.GL_UNSIGNED_SHORT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+ }
+
+ private void setupBoundingBuffers(){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ ShortBuffer indicies = Buffers.newDirectShortBuffer(6);
+ indicies.put((short) 0); indicies.put((short) 1); indicies.put((short) 3);
+ indicies.put((short) 1); indicies.put((short) 2); indicies.put((short) 3);
+ indicies.rewind();
+
+ FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(4 * 3);
+ FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(4 * 2);
+
+ verticesBuffer.put(box.getLow()[0]);
+ verticesBuffer.put(box.getLow()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+ texCoordBuffer.put(5);
+ texCoordBuffer.put(5);
+
+ verticesBuffer.put(box.getLow()[0]);
+ verticesBuffer.put(box.getHigh()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+
+ texCoordBuffer.put(5);
+ texCoordBuffer.put(6);
+
+ verticesBuffer.put(box.getHigh()[0]);
+ verticesBuffer.put(box.getHigh()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+
+ texCoordBuffer.put(6);
+ texCoordBuffer.put(6);
+
+ verticesBuffer.put(box.getHigh()[0]);
+ verticesBuffer.put(box.getLow()[1]);
+ verticesBuffer.put(box.getLow()[2]);
+
+ texCoordBuffer.put(6);
+ texCoordBuffer.put(5);
+
+ verticesBuffer.rewind();
+ texCoordBuffer.rewind();
+
+ t_vboIds = IntBuffer.allocate(3);
+ gl.glGenBuffers(numBuffers, t_vboIds);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(0)); // vertices
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, 4 * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, t_vboIds.get(1)); //texture
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, 4 * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, t_vboIds.get(2)); //triangles
+ gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 4 * 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ private void initFBOTexture(PMVMatrix m, int width, int hight){
+ tex_height_c = (int)(tex_width_c*box.getHeight()/box.getWidth());
+ // tex_height_c = tex_width_c;
+ System.out.println("FBO Size: "+tex_height_c+"x"+tex_width_c);
+ System.out.println("FBO Scale: " + m.glGetMatrixf().get(0) +" " + m.glGetMatrixf().get(5));
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ if(fbo[0] > 0) {
+ gl.glDeleteFramebuffers(1, fbo, 0);
+ fbo[0] = 0;
+ }
+ if(texture[0]>0) {
+ gl.glDeleteTextures(1, texture, 0);
+ texture[0] = 0;
+ }
+
+ gl.glGenFramebuffers(1, fbo, 0);
+ gl.glGenTextures(1, texture, 0);
+ gl.glGenRenderbuffers(1,rbo_depth, 0);
+ System.out.println("FBO: fbo " + fbo[0] + ", tex " + texture[0] + ", depth " + rbo_depth[0]);
+
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbo[0]);
+ gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, texture[0]);
+ gl.glTexImage2D(GL2ES2.GL_TEXTURE_2D, 0, GL2ES2.GL_RGBA, tex_width_c,
+ tex_height_c, 0, GL2ES2.GL_RGBA, GL2ES2.GL_UNSIGNED_BYTE, null);
+
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_MIN_FILTER, GL2ES2.GL_LINEAR);
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_MAG_FILTER, GL2ES2.GL_LINEAR);
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_WRAP_S, GL2ES2.GL_CLAMP_TO_EDGE);
+ gl.glTexParameterf(GL2ES2.GL_TEXTURE_2D, GL2ES2.GL_TEXTURE_WRAP_T, GL2ES2.GL_CLAMP_TO_EDGE);
+
+ gl.glFramebufferTexture2D(GL2GL3.GL_DRAW_FRAMEBUFFER, GL2ES2.GL_COLOR_ATTACHMENT0,
+ GL2ES2.GL_TEXTURE_2D, texture[0], 0);
+
+ // Set up the depth buffer
+ gl.glBindRenderbuffer(GL2ES2.GL_RENDERBUFFER, rbo_depth[0]);
+ gl.glRenderbufferStorage(GL2ES2.GL_RENDERBUFFER, GL2ES2.GL_DEPTH_COMPONENT, tex_width_c, tex_height_c);
+ gl.glFramebufferRenderbuffer(GL2ES2.GL_FRAMEBUFFER, GL2ES2.GL_DEPTH_COMPONENT, GL2ES2.GL_RENDERBUFFER, rbo_depth[0]);
+
+ int status = gl.glCheckFramebufferStatus(GL2ES2.GL_FRAMEBUFFER);
+ if(status != GL2ES2.GL_FRAMEBUFFER_COMPLETE){
+ System.err.println("Cant Create R2T pass!");
+ }
+
+ //render texture
+ PMVMatrix tex_matrix = new PMVMatrix();
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbo[0]);
+ gl.glViewport(0, 0, tex_width_c, tex_height_c);
+ tex_matrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ tex_matrix.glLoadIdentity();
+ tex_matrix.glOrthof(box.getLow()[0], box.getHigh()[0], box.getLow()[1], box.getHigh()[1], -1, 1);
+
+ if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, tex_matrix.glGetPMvMatrixf()))){
+ System.out.println("Cnt set tex based mat");
+ }
+
+ gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ gl.glClear(GL2ES2.GL_COLOR_BUFFER_BIT | GL2ES2.GL_DEPTH_BUFFER_BIT);
+ renderRegion();
+
+ gl.glBindFramebuffer(GL2ES2.GL_FRAMEBUFFER, 0);
+ gl.glBindTexture(GL2ES2.GL_TEXTURE_2D, 0);
+
+ setupBoundingBuffers();
+ }
+
+ private void renderRegion(){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0));
+ gl.glEnableVertexAttribArray(VERTEX_ATTR_IDX);
+ gl.glVertexAttribPointer(VERTEX_ATTR_IDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1));
+ gl.glEnableVertexAttribArray(TEXCOORD_ATTR_IDX);
+ gl.glVertexAttribPointer(TEXCOORD_ATTR_IDX, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2));
+ gl.glDrawElements(GL2ES2.GL_TRIANGLES, triangles.size() * 3, GL2ES2.GL_UNSIGNED_SHORT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+ }
+
+ public void addTriangles(ArrayList<Triangle> tris) {
+ triangles.addAll(tris);
+ dirty = true;
+ }
+
+ public int getNumVertices(){
+ return numVertices;
+ }
+
+ public void addVertices(ArrayList<Vertex> verts){
+ vertices.addAll(verts);
+ numVertices = vertices.size();
+ dirty = true;
+ }
+
+ public boolean isDirty(){
+ return dirty;
+ }
+
+ public void destroy() {
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ gl.glDeleteBuffers(numBuffers, vboIds);
+ gl.glDeleteFramebuffers(1, fbo, 0);
+ fbo[0] = 0;
+ gl.glDeleteTextures(1, texture, 0);
+ texture[0] = 0;
+ gl.glDeleteRenderbuffers(1, rbo_depth, 0);
+ rbo_depth[0] = 0;
+ }
+
+ public boolean isFlipped() {
+ return flipped;
+ }
+
+ public void setFlipped(boolean flipped) {
+ this.flipped = flipped;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java
new file mode 100644
index 000000000..701549d46
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/opengl/VBORegionSPES2.java
@@ -0,0 +1,185 @@
+/**
+ * Copyright 2010 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.curve.opengl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLContext;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.opengl.util.PMVMatrix;
+
+public class VBORegionSPES2 implements Region{
+ private int numVertices = 0;
+ private IntBuffer vboIds;
+
+ private ArrayList<Triangle> triangles = new ArrayList<Triangle>();
+ private ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+
+ private GLContext context;
+
+ private int numBuffers = 3;
+
+ private boolean flipped = false;
+ private boolean dirty = false;
+
+ public VBORegionSPES2(GLContext context){
+ this.context =context;
+ }
+
+ public void update(){
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ ShortBuffer indicies = Buffers.newDirectShortBuffer(triangles.size() * 3);
+
+ for(Triangle t:triangles){
+ final Vertex[] t_vertices = t.getVertices();
+
+ if(t_vertices[0].getId() == Integer.MAX_VALUE){
+ t_vertices[0].setId(numVertices++);
+ t_vertices[1].setId(numVertices++);
+ t_vertices[2].setId(numVertices++);
+
+ vertices.add(t.getVertices()[0]);
+ vertices.add(t.getVertices()[1]);
+ vertices.add(t.getVertices()[2]);
+
+ indicies.put((short) t.getVertices()[0].getId());
+ indicies.put((short) t.getVertices()[1].getId());
+ indicies.put((short) t.getVertices()[2].getId());
+ }
+ else{
+ Vertex v1 = t_vertices[0];
+ Vertex v2 = t_vertices[1];
+ Vertex v3 = t_vertices[2];
+
+ indicies.put((short) v1.getId());
+ indicies.put((short) v2.getId());
+ indicies.put((short) v3.getId());
+ }
+ }
+ indicies.rewind();
+
+ FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 3);
+ for(Vertex v:vertices){
+ verticesBuffer.put(v.getX());
+ if(flipped){
+ verticesBuffer.put(-1*v.getY());
+ }
+ else{
+ verticesBuffer.put(v.getY());
+ }
+ verticesBuffer.put(v.getZ());
+ }
+ verticesBuffer.rewind();
+
+ FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 2);
+ for(Vertex v:vertices){
+ float[] tex = v.getTexCoord();
+ texCoordBuffer.put(tex[0]);
+ texCoordBuffer.put(tex[1]);
+ }
+ texCoordBuffer.rewind();
+
+ vboIds = IntBuffer.allocate(numBuffers);
+ gl.glGenBuffers(numBuffers, vboIds);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0)); // vertices
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1)); //texture
+ gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); //triangles
+ gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, triangles.size()* 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ dirty = false;
+ }
+
+ private void render() {
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0));
+ gl.glEnableVertexAttribArray(VERTEX_ATTR_IDX);
+ gl.glVertexAttribPointer(VERTEX_ATTR_IDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1));
+ gl.glEnableVertexAttribArray(TEXCOORD_ATTR_IDX);
+ gl.glVertexAttribPointer(TEXCOORD_ATTR_IDX, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2));
+ gl.glDrawElements(GL2ES2.GL_TRIANGLES, triangles.size() * 3, GL2ES2.GL_UNSIGNED_SHORT, 0);
+
+ gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0);
+ }
+
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width){
+ render();
+ }
+
+ public void addTriangles(ArrayList<Triangle> tris) {
+ triangles.addAll(tris);
+ dirty = true;
+ }
+
+ public int getNumVertices(){
+ return numVertices;
+ }
+
+ public void addVertices(ArrayList<Vertex> verts){
+ vertices.addAll(verts);
+ numVertices = vertices.size();
+ dirty = true;
+ }
+
+ public boolean isDirty(){
+ return dirty;
+ }
+
+ public void destroy() {
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ gl.glDeleteBuffers(numBuffers, vboIds);
+ }
+
+ public boolean isFlipped() {
+ return flipped;
+ }
+
+ public void setFlipped(boolean flipped) {
+ this.flipped = flipped;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.fp b/src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.fp
new file mode 100644
index 000000000..2b3a0ce1d
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.fp
@@ -0,0 +1,99 @@
+//#version 100
+
+uniform float p1y;
+uniform float g_alpha;
+uniform vec3 g_color;
+uniform float a_strength;
+
+varying vec2 v_texCoord;
+
+vec3 b_color = vec3(0.0, 0.0, 0.0);
+
+uniform sampler2D texture;
+vec4 weights = vec4(0.075, 0.06, 0.045, 0.025);
+
+void main (void)
+{
+ vec2 rtex = vec2(abs(v_texCoord.x),abs(v_texCoord.y));
+ vec3 c = g_color;
+
+ float alpha = 0.0;
+
+ if((v_texCoord.x == 0.0) && (v_texCoord.y == 0.0)){
+ alpha = g_alpha;
+ }
+ else if((v_texCoord.x >= 5.0)){
+ vec2 dfx = dFdx(v_texCoord);
+ vec2 dfy = dFdy(v_texCoord);
+
+ vec2 size = 1.0/textureSize(texture,0); //version 130
+ rtex -= 5.0;
+ vec4 t = texture2D(texture, rtex)* 0.18;
+
+ t += texture2D(texture, rtex + size*(vec2(1, 0)))*weights.x;
+ t += texture2D(texture, rtex - size*(vec2(1, 0)))*weights.x;
+ t += texture2D(texture, rtex + size*(vec2(0, 1)))*weights.x;
+ t += texture2D(texture, rtex - size*(vec2(0, 1)))*weights.x;
+
+ t += texture2D(texture, rtex + 2.0*size*(vec2(1, 0))) *weights.y;
+ t += texture2D(texture, rtex - 2.0*size*(vec2(1, 0)))*weights.y;
+ t += texture2D(texture, rtex + 2.0*size*(vec2(0, 1)))*weights.y;
+ t += texture2D(texture, rtex - 2.0*size*(vec2(0, 1)))*weights.y;
+
+ t += texture2D(texture, rtex + 3.0*size*(vec2(1, 0))) *weights.z;
+ t += texture2D(texture, rtex - 3.0*size*(vec2(1, 0)))*weights.z;
+ t += texture2D(texture, rtex + 3.0*size*(vec2(0, 1)))*weights.z;
+ t += texture2D(texture, rtex - 3.0*size*(vec2(0, 1)))*weights.z;
+
+ t += texture2D(texture, rtex + 4.0*size*(vec2(1, 0))) *weights.w;
+ t += texture2D(texture, rtex - 4.0*size*(vec2(1, 0)))*weights.w;
+ t += texture2D(texture, rtex + 4.0*size*(vec2(0, 1)))*weights.w;
+ t += texture2D(texture, rtex - 4.0*size*(vec2(0, 1)))*weights.w;
+
+ if(t.w == 0.0){
+ discard;
+ }
+
+ c = t.xyz;
+ alpha = g_alpha* t.w;
+ }
+ ///////////////////////////////////////////////////////////
+ else if ((v_texCoord.x > 0.0) && (rtex.y > 0.0 || rtex.x == 1.0)){
+ vec2 dtx = dFdx(rtex);
+ vec2 dty = dFdy(rtex);
+
+ rtex.y -= 0.1;
+ if(rtex.y < 0.0) {
+ if(v_texCoord.y < 0.0)
+ discard;
+ else{
+ rtex.y = 0.0;
+ }
+ }
+
+ vec2 f = vec2((dtx.y - 2.0*p1y*dtx.x + 4.0*p1y*rtex.x*dtx.x), (dty.y - 2.0*p1y*dty.x + 4.0*p1y*rtex.x*dty.x));
+
+ float position = rtex.y - ((2.0 * rtex.x * p1y) * (1.0 - rtex.x));
+ float d = position/(length(f));
+
+ float a = (0.5 - d * sign(v_texCoord.y));
+
+
+ if (a >= 1.0) {
+ alpha = g_alpha;
+ // c = vec3(1.0,1.0,1.0);
+ }
+ else if (a <= 0.0) {
+ alpha = 0.0;//discard;
+ // c = vec3(0.0,0.0,0.0);
+
+ }
+ else {
+ alpha = g_alpha*a;
+ // c = vec3(a,a,a);
+ mix(b_color,g_color, a);
+ }
+ }
+
+ gl_FragColor = vec4(c, alpha);
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.vp b/src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.vp
new file mode 100644
index 000000000..bc9ecb41e
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/opengl/shader/curverenderer01.vp
@@ -0,0 +1,13 @@
+//#version 100
+
+uniform mat4 mgl_PMVMatrix[2];
+attribute vec4 v_position;
+attribute vec2 texCoord;
+
+varying vec2 v_texCoord;
+
+void main(void)
+{
+ gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * v_position;
+ v_texCoord = texCoord.st;
+} \ No newline at end of file
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java b/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java
new file mode 100644
index 000000000..5dae296e5
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/tess/GraphOutline.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright 2010 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.curve.tess;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Vertex;
+
+public class GraphOutline {
+ final private Outline outline;
+ final private ArrayList<GraphVertex> controlpoints = new ArrayList<GraphVertex>(3);
+
+ public GraphOutline(){
+ this.outline = new Outline();
+ }
+
+ /**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
+ */
+ public GraphOutline(Outline ol){
+ this.outline = ol;
+ ArrayList<Vertex> vertices = this.outline.getVertices();
+ for(Vertex v:vertices){
+ this.controlpoints.add(new GraphVertex(v));
+ }
+ }
+
+ public Outline getOutline() {
+ return outline;
+ }
+
+ /*public void setOutline(Outline<T> outline) {
+ this.outline = outline;
+ }*/
+
+
+ public ArrayList<GraphVertex> getGraphPoint() {
+ return controlpoints;
+ }
+
+ public ArrayList<Vertex> getPoints() {
+ return outline.getVertices();
+ }
+
+ /*public void setControlpoints(ArrayList<GraphPoint<T>> controlpoints) {
+ this.controlpoints = controlpoints;
+ }*/
+
+ public void addVertex(GraphVertex v) {
+ controlpoints.add(v);
+ outline.addVertex(v.getPoint());
+ }
+
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/GraphVertex.java b/src/jogl/classes/jogamp/graph/curve/tess/GraphVertex.java
new file mode 100644
index 000000000..b9f95a0e7
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/tess/GraphVertex.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2010 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.curve.tess;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Vertex;
+
+public class GraphVertex {
+ private Vertex point;
+ private ArrayList<HEdge> edges = null;
+ private boolean boundaryContained = false;
+
+ public GraphVertex(Vertex point) {
+ this.point = point;
+ }
+
+ public Vertex getPoint() {
+ return point;
+ }
+
+ public float getX(){
+ return point.getX();
+ }
+
+ public float getY(){
+ return point.getY();
+ }
+
+ public float getZ(){
+ return point.getZ();
+ }
+ public float[] getCoord() {
+ return point.getCoord();
+ }
+
+ public void setPoint(Vertex point) {
+ this.point = point;
+ }
+
+ public ArrayList<HEdge> getEdges() {
+ return edges;
+ }
+
+ public void setEdges(ArrayList<HEdge> edges) {
+ this.edges = edges;
+ }
+
+ public void addEdge(HEdge edge){
+ if(edges == null){
+ edges = new ArrayList<HEdge>();
+ }
+ edges.add(edge);
+ }
+ public void removeEdge(HEdge edge){
+ if(edges == null)
+ return;
+ edges.remove(edge);
+ if(edges.size() == 0){
+ edges = null;
+ }
+ }
+ public HEdge findNextEdge(GraphVertex nextVert){
+ for(HEdge e:edges){
+ if(e.getNext().getGraphPoint() == nextVert){
+ return e;
+ }
+ }
+ return null;
+ }
+ public HEdge findBoundEdge(){
+ for(HEdge e:edges){
+ if((e.getType() == HEdge.BOUNDARY) || (e.getType() == HEdge.HOLE)){
+ return e;
+ }
+ }
+ return null;
+ }
+ public HEdge findPrevEdge(GraphVertex prevVert){
+ for(HEdge e:edges){
+ if(e.getPrev().getGraphPoint() == prevVert){
+ return e;
+ }
+ }
+ return null;
+ }
+
+ public boolean isBoundaryContained() {
+ return boundaryContained;
+ }
+
+ public void setBoundaryContained(boolean boundaryContained) {
+ this.boundaryContained = boundaryContained;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/HEdge.java b/src/jogl/classes/jogamp/graph/curve/tess/HEdge.java
new file mode 100644
index 000000000..d1bcc6e17
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/tess/HEdge.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright 2010 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.curve.tess;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+
+
+public class HEdge {
+ public static int BOUNDARY = 3;
+ public static int INNER = 1;
+ public static int HOLE = 2;
+
+ private GraphVertex vert;
+ private HEdge prev = null;
+ private HEdge next = null;
+ private HEdge sibling = null;
+ private int type = BOUNDARY;
+ private Triangle triangle = null;
+
+ public HEdge(GraphVertex vert, int type) {
+ this.vert = vert;
+ this.type = type;
+ }
+
+ public HEdge(GraphVertex vert, HEdge prev, HEdge next, HEdge sibling, int type) {
+ this.vert = vert;
+ this.prev = prev;
+ this.next = next;
+ this.sibling = sibling;
+ this.type = type;
+ }
+
+ public HEdge(GraphVertex vert, HEdge prev, HEdge next, HEdge sibling, int type, Triangle triangle) {
+ this.vert = vert;
+ this.prev = prev;
+ this.next = next;
+ this.sibling = sibling;
+ this.type = type;
+ this.triangle = triangle;
+ }
+
+ public GraphVertex getGraphPoint() {
+ return vert;
+ }
+
+ public void setVert(GraphVertex vert) {
+ this.vert = vert;
+ }
+
+ public HEdge getPrev() {
+ return prev;
+ }
+
+ public void setPrev(HEdge prev) {
+ this.prev = prev;
+ }
+
+ public HEdge getNext() {
+ return next;
+ }
+
+ public void setNext(HEdge next) {
+ this.next = next;
+ }
+
+ public HEdge getSibling() {
+ return sibling;
+ }
+
+ public void setSibling(HEdge sibling) {
+ this.sibling = sibling;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public Triangle getTriangle() {
+ return triangle;
+ }
+
+ public void setTriangle(Triangle triangle) {
+ this.triangle = triangle;
+ }
+
+ public static <T extends Vertex> void connect(HEdge first, HEdge next){
+ first.setNext(next);
+ next.setPrev(first);
+ }
+
+ public static <T extends Vertex> void makeSiblings(HEdge first, HEdge second){
+ first.setSibling(second);
+ second.setSibling(first);
+ }
+
+ public boolean vertexOnCurveVertex(){
+ return vert.getPoint().isOnCurve();
+ }
+
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/tess/Loop.java b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
new file mode 100644
index 000000000..fd7736a20
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/tess/Loop.java
@@ -0,0 +1,373 @@
+/**
+ * Copyright 2010 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.curve.tess;
+
+import java.util.ArrayList;
+
+
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.math.VectorUtil;
+
+public class Loop {
+ private HEdge root = null;
+ private AABBox box = new AABBox();
+ private GraphOutline initialOutline = null;
+
+ public Loop(GraphOutline polyline, int direction){
+ initialOutline = polyline;
+ this.root = initFromPolyline(initialOutline, direction);
+ }
+
+ public HEdge getHEdge(){
+ return root;
+ }
+
+ public Triangle cut(boolean delaunay){
+ if(isSimplex()){
+ Triangle t = new Triangle(root.getGraphPoint().getPoint(), root.getNext().getGraphPoint().getPoint(),
+ root.getNext().getNext().getGraphPoint().getPoint());
+ t.setVerticesBoundary(checkVerticesBoundary(root));
+ return t;
+ }
+ HEdge prev = root.getPrev();
+ HEdge next1 = root.getNext();
+
+ HEdge next2 = findClosestValidNeighbor(next1.getNext(), delaunay);
+ if(next2 == null){
+ root = root.getNext();
+ return null;
+ }
+
+ GraphVertex v1 = root.getGraphPoint();
+ GraphVertex v2 = next1.getGraphPoint();
+ GraphVertex v3 = next2.getGraphPoint();
+
+ HEdge v3Edge = new HEdge(v3, HEdge.INNER);
+
+ HEdge.connect(v3Edge, root);
+ HEdge.connect(next1, v3Edge);
+
+ HEdge v3EdgeSib = v3Edge.getSibling();
+ if(v3EdgeSib == null){
+ v3EdgeSib = new HEdge(v3Edge.getNext().getGraphPoint(), HEdge.INNER);
+ HEdge.makeSiblings(v3Edge, v3EdgeSib);
+ }
+
+ HEdge.connect(prev, v3EdgeSib);
+ HEdge.connect(v3EdgeSib, next2);
+
+ Triangle t = createTriangle(v1.getPoint(), v2.getPoint(), v3.getPoint(), root);
+ this.root = next2;
+ return t;
+ }
+
+ public boolean isSimplex(){
+ return (root.getNext().getNext().getNext() == root);
+ }
+
+ /**Create a connected list of half edges (loop)
+ * from the boundary profile
+ * @param direction requested winding of edges (CCW or CW)
+ */
+ private HEdge initFromPolyline(GraphOutline outline, int direction){
+ ArrayList<GraphVertex> vertices = outline.getGraphPoint();
+
+ if(vertices.size()<3) {
+ throw new IllegalArgumentException("outline's vertices < 3: " + vertices.size());
+ }
+ boolean isCCW = VectorUtil.ccw(vertices.get(0).getPoint(), vertices.get(1).getPoint(),
+ vertices.get(2).getPoint());
+ boolean invert = isCCW && (direction == VectorUtil.CW);
+
+ HEdge firstEdge = null;
+ HEdge lastEdge = null;
+ int index =0;
+ int max = vertices.size();
+
+ int edgeType = HEdge.BOUNDARY;
+ if(invert){
+ index = vertices.size() -1;
+ max = -1;
+ edgeType = HEdge.HOLE;
+ }
+
+ while(index != max){
+ GraphVertex v1 = vertices.get(index);
+ box.resize(v1.getX(), v1.getY(), v1.getZ());
+
+ 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){
+ edge.setNext(firstEdge);
+ firstEdge.setPrev(edge);
+ }
+ }
+ else if (index == 0){
+ edge.setNext(firstEdge);
+ firstEdge.setPrev(edge);
+ }
+
+ lastEdge = edge;
+
+ if(!invert){
+ index++;
+ }
+ else{
+ index--;
+ }
+ }
+ return firstEdge;
+ }
+
+ public void addConstraintCurve(GraphOutline polyline) {
+ // GraphOutline outline = new GraphOutline(polyline);
+ /**needed to generate vertex references.*/
+ initFromPolyline(polyline, VectorUtil.CW);
+
+ GraphVertex v3 = locateClosestVertex(polyline);
+ HEdge v3Edge = v3.findBoundEdge();
+ HEdge v3EdgeP = v3Edge.getPrev();
+ HEdge crossEdge = new HEdge(root.getGraphPoint(), HEdge.INNER);
+
+ HEdge.connect(root.getPrev(), crossEdge);
+ HEdge.connect(crossEdge, v3Edge);
+
+ HEdge crossEdgeSib = crossEdge.getSibling();
+ if(crossEdgeSib == null) {
+ crossEdgeSib = new HEdge(crossEdge.getNext().getGraphPoint(), HEdge.INNER);
+ HEdge.makeSiblings(crossEdge, crossEdgeSib);
+ }
+
+ HEdge.connect(v3EdgeP, crossEdgeSib);
+ HEdge.connect(crossEdgeSib, root);
+ }
+
+ /** Locates the vertex and update the loops root
+ * to have (root + vertex) as closest pair
+ * @param polyline the control polyline
+ * to search for closestvertices
+ * @return the vertex that is closest to the newly set root Hedge.
+ */
+ private GraphVertex locateClosestVertex(GraphOutline polyline) {
+ HEdge closestE = null;
+ GraphVertex closestV = null;
+
+ float minDistance = Float.MAX_VALUE;
+ boolean inValid = false;
+ ArrayList<GraphVertex> initVertices = initialOutline.getGraphPoint();
+ ArrayList<GraphVertex> vertices = polyline.getGraphPoint();
+
+ for(int i=0; i< initVertices.size()-1; i++){
+ GraphVertex v = initVertices.get(i);
+ GraphVertex nextV = initVertices.get(i+1);
+ for(GraphVertex cand:vertices){
+ float distance = VectorUtil.computeLength(v.getCoord(), cand.getCoord());
+ if(distance < minDistance){
+ for (GraphVertex vert:vertices){
+ if(vert == v || vert == nextV || vert == cand)
+ continue;
+ inValid = VectorUtil.inCircle(v.getPoint(), nextV.getPoint(),
+ cand.getPoint(), vert.getPoint());
+ if(inValid){
+ break;
+ }
+ }
+ if(!inValid){
+ closestV = cand;
+ minDistance = distance;
+ closestE = v.findBoundEdge();
+ }
+ }
+
+ }
+ }
+
+ if(closestE != null){
+ root = closestE;
+ }
+
+ return closestV;
+ }
+
+ private HEdge findClosestValidNeighbor(HEdge edge, boolean delaunay) {
+ HEdge next = root.getNext();
+
+ if(!VectorUtil.ccw(root.getGraphPoint().getPoint(), next.getGraphPoint().getPoint(),
+ edge.getGraphPoint().getPoint())){
+ return null;
+ }
+
+ HEdge candEdge = edge;
+ boolean inValid = false;
+
+ if(delaunay){
+ Vertex cand = candEdge.getGraphPoint().getPoint();
+ HEdge e = candEdge.getNext();
+ while (e != candEdge){
+ if(e.getGraphPoint() == root.getGraphPoint()
+ || e.getGraphPoint() == next.getGraphPoint()
+ || e.getGraphPoint().getPoint() == cand){
+ e = e.getNext();
+ continue;
+ }
+ inValid = VectorUtil.inCircle(root.getGraphPoint().getPoint(), next.getGraphPoint().getPoint(),
+ cand, e.getGraphPoint().getPoint());
+ if(inValid){
+ break;
+ }
+ e = e.getNext();
+ }
+ }
+ if(!inValid){
+ return candEdge;
+ }
+ return null;
+ }
+
+ /** Create a triangle from the param vertices only if
+ * the triangle is valid. IE not outside region.
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @param v3 vertex 3
+ * @param root and edge of this triangle
+ * @return the triangle iff it satisfies, null otherwise
+ */
+ private Triangle createTriangle(Vertex v1, Vertex v2, Vertex v3, HEdge rootT){
+ Triangle t = new Triangle(v1, v2, v3);
+ t.setVerticesBoundary(checkVerticesBoundary(rootT));
+ return t;
+ }
+
+ private boolean[] checkVerticesBoundary(HEdge rootT) {
+ boolean[] boundary = new boolean[3];
+ HEdge e1 = rootT;
+ HEdge e2 = rootT.getNext();
+ HEdge e3 = rootT.getNext().getNext();
+
+ if(e1.getGraphPoint().isBoundaryContained()){
+ boundary[0] = true;
+ }
+ if(e2.getGraphPoint().isBoundaryContained()){
+ boundary[1] = true;
+ }
+ if(e3.getGraphPoint().isBoundaryContained()){
+ boundary[2] = true;
+ }
+ return boundary;
+ }
+
+
+ /** Check if vertex inside the Loop
+ * @param vertex the Vertex
+ * @return true if the vertex is inside, false otherwise
+ */
+ public boolean checkInside(Vertex vertex) {
+ if(!box.contains(vertex.getX(), vertex.getY(), vertex.getZ())){
+ return false;
+ }
+
+ float[] center = box.getCenter();
+
+ int hits = 0;
+ HEdge current = root;
+ HEdge next = root.getNext();
+ while(next!= root){
+ if(current.getType() == HEdge.INNER || next.getType() == HEdge.INNER){
+ current = next;
+ next = current.getNext();
+ continue;
+ }
+ Vertex vert1 = current.getGraphPoint().getPoint();
+ Vertex vert2 = next.getGraphPoint().getPoint();
+
+ /** The ray is P0+s*D0, where P0 is the ray origin, D0 is a direction vector and s >= 0.
+ * The segment is P1+t*D1, where P1 and P1+D1 are the endpoints, and 0 <= t <= 1.
+ * perp(x,y) = (y,-x).
+ * if Dot(perp(D1),D0) is not zero,
+ * s = Dot(perp(D1),P1-P0)/Dot(perp(D1),D0)
+ * t = Dot(perp(D0),P1-P0)/Dot(perp(D1),D0)
+ */
+
+ float[] d0 = new float[]{center[0] - vertex.getX(), center[1]-vertex.getY(),
+ center[2]-vertex.getZ()};
+ float[] d1 = {vert2.getX() - vert1.getX(), vert2.getY() - vert1.getY(),
+ vert2.getZ() - vert1.getZ()};
+
+ float[] prep_d1 = {d1[1],-1*d1[0], d1[2]};
+ float[] prep_d0 = {d0[1],-1*d0[0], d0[2]};
+
+ float[] p0p1 = new float[]{vert1.getX() - vertex.getX(), vert1.getY() - vertex.getY(),
+ vert1.getZ() - vertex.getZ()};
+
+ float dotD1D0 = VectorUtil.dot(prep_d1, d0);
+ if(dotD1D0 == 0){
+ /** ray parallel to segment */
+ current = next;
+ next = current.getNext();
+ continue;
+ }
+
+ float s = VectorUtil.dot(prep_d1,p0p1)/dotD1D0;
+ float t = VectorUtil.dot(prep_d0,p0p1)/dotD1D0;
+
+ if(s >= 0 && t >= 0 && t<= 1){
+ hits++;
+ }
+ current = next;
+ next = current.getNext();
+ }
+
+ if(hits % 2 != 0){
+ /** check if hit count is even */
+ return true;
+ }
+ return false;
+ }
+
+ public int computeLoopSize(){
+ int size = 0;
+ HEdge e = root;
+ do{
+ size++;
+ e = e.getNext();
+ }while(e != root);
+ return size;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java
new file mode 100644
index 000000000..36ba57244
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright 2010 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.curve.text;
+
+import java.util.ArrayList;
+
+import jogamp.graph.geom.plane.PathIterator;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.math.Quaternion;
+
+public class GlyphShape {
+
+ private Quaternion quat= null;
+ private int numVertices = 0;
+ private OutlineShape shape = null;
+
+ /** Create a new Glyph shape
+ * based on Parametric curve control polyline
+ */
+ public GlyphShape(Vertex.Factory<? extends Vertex> factory){
+ shape = new OutlineShape(factory);
+ }
+
+ /** Create a GlyphShape from a font Path Iterator
+ * @param pathIterator the path iterator
+ *
+ * @see PathIterator
+ */
+ public GlyphShape(Vertex.Factory<? extends Vertex> factory, PathIterator pathIterator){
+ this(factory);
+
+ if(null != pathIterator){
+ while(!pathIterator.isDone()){
+ float[] coords = new float[6];
+ int segmentType = pathIterator.currentSegment(coords);
+ addOutlineVerticesFromGlyphVector(coords, segmentType);
+
+ pathIterator.next();
+ }
+ }
+ shape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+ }
+
+ public final Vertex.Factory<? extends Vertex> vertexFactory() { return shape.vertexFactory(); }
+
+ private void addVertexToLastOutline(Vertex vertex){
+ shape.addVertex(vertex);
+ }
+
+ private void addOutlineVerticesFromGlyphVector(float[] coords, int segmentType){
+ if(segmentType == PathIterator.SEG_MOVETO){
+ if(!shape.getLastOutline().isEmpty()){
+ shape.addEmptyOutline();
+ }
+ Vertex vert = vertexFactory().create(coords[0],coords[1]);
+ vert.setOnCurve(true);
+ addVertexToLastOutline(vert);
+
+ numVertices++;
+ }
+ else if(segmentType == PathIterator.SEG_LINETO){
+ Vertex vert1 = vertexFactory().create(coords[0],coords[1]);
+ vert1.setOnCurve(true);
+ addVertexToLastOutline(vert1);
+
+ numVertices++;
+ }
+ else if(segmentType == PathIterator.SEG_QUADTO){
+ Vertex vert1 = vertexFactory().create(coords[0],coords[1]);
+ vert1.setOnCurve(false);
+ addVertexToLastOutline(vert1);
+
+ Vertex vert2 = vertexFactory().create(coords[2],coords[3]);
+ vert2.setOnCurve(true);
+ addVertexToLastOutline(vert2);
+
+ numVertices+=2;
+ }
+ else if(segmentType == PathIterator.SEG_CUBICTO){
+ Vertex vert1 = vertexFactory().create(coords[0],coords[1]);
+ vert1.setOnCurve(false);
+ addVertexToLastOutline(vert1);
+
+ Vertex vert2 = vertexFactory().create(coords[2],coords[3]);
+ vert2.setOnCurve(false);
+ addVertexToLastOutline(vert2);
+
+ Vertex vert3 = vertexFactory().create(coords[4],coords[5]);
+ vert3.setOnCurve(true);
+ addVertexToLastOutline(vert3);
+
+ numVertices+=3;
+ }
+ else if(segmentType == PathIterator.SEG_CLOSE){
+ shape.closeLastOutline();
+ }
+ }
+
+ public int getNumVertices() {
+ return numVertices;
+ }
+
+ /** Get the rotational Quaternion attached to this Shape
+ * @return the Quaternion Object
+ */
+ public Quaternion getQuat() {
+ return quat;
+ }
+
+ /** Set the Quaternion that shall defien the rotation
+ * of this shape.
+ * @param quat
+ */
+ public void setQuat(Quaternion quat) {
+ this.quat = quat;
+ }
+
+ /** Triangluate the glyph shape
+ * @param sharpness sharpness of the curved regions default = 0.5
+ * @return ArrayList of triangles which define this shape
+ */
+ public ArrayList<Triangle> triangulate(float sharpness){
+ return shape.triangulate(sharpness);
+ }
+
+ /** Get the list of Vertices of this Object
+ * @return arrayList of Vertices
+ */
+ public ArrayList<Vertex> getVertices(){
+ return shape.getVertices();
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java
new file mode 100644
index 000000000..808e3a415
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright 2010 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.curve.text;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+import javax.media.opengl.GLContext;
+
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+import jogamp.graph.geom.plane.PathIterator;
+
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.RegionFactory;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public class GlyphString {
+ private final Vertex.Factory<? extends Vertex> pointFactory;
+ private ArrayList<GlyphShape> glyphs = new ArrayList<GlyphShape>();
+ private String str = "";
+ private String fontname = "";
+ private Region region;
+
+ private SVertex origin = new SVertex();
+
+ /** Create a new GlyphString object
+ * @param fontname the name of the font that this String is
+ * associated with
+ * @param str the string object
+ */
+ public GlyphString(Vertex.Factory<? extends Vertex> factory, String fontname, String str){
+ pointFactory = factory;
+ this.fontname = fontname;
+ this.str = str;
+ }
+
+ public final Vertex.Factory<? extends Vertex> pointFactory() { return pointFactory; }
+
+ public void addGlyphShape(GlyphShape glyph){
+ glyphs.add(glyph);
+ }
+ public String getString(){
+ return str;
+ }
+
+ /** Creates the Curve based Glyphs from a Font
+ * @param paths a list of FontPath2D objects that define the outline
+ * @param affineTransform a global affine transformation applied to the paths.
+ */
+ public void createfromFontPath(Path2D[] paths, AffineTransform affineTransform){
+ final int numGlyps = paths.length;
+ for (int index=0;index<numGlyps;index++){
+ if(paths[index] == null){
+ continue;
+ }
+ PathIterator iterator = paths[index].iterator(affineTransform);
+ GlyphShape glyphShape = new GlyphShape(pointFactory, iterator);
+
+ if(glyphShape.getNumVertices() < 3) {
+ continue;
+ }
+ addGlyphShape(glyphShape);
+ }
+ }
+
+ private ArrayList<Triangle> initializeTriangles(float sharpness){
+ ArrayList<Triangle> triangles = new ArrayList<Triangle>();
+ for(GlyphShape glyph:glyphs){
+ ArrayList<Triangle> tris = glyph.triangulate(sharpness);
+ triangles.addAll(tris);
+ }
+ return triangles;
+ }
+
+ /** Generate a OGL Region to represent this Object.
+ * @param context the GLContext which the region is defined by.
+ * @param shaprness the curvature sharpness of the object.
+ * @param st shader state
+ */
+ public void generateRegion(GLContext context, float shaprness, ShaderState st, int type){
+ region = RegionFactory.create(context, st, type);
+ region.setFlipped(true);
+
+ ArrayList<Triangle> tris = initializeTriangles(shaprness);
+ region.addTriangles(tris);
+
+ int numVertices = region.getNumVertices();
+ for(GlyphShape glyph:glyphs){
+ ArrayList<Vertex> gVertices = glyph.getVertices();
+ for(Vertex vert:gVertices){
+ vert.setId(numVertices++);
+ }
+ region.addVertices(gVertices);
+ }
+
+ /** initialize the region */
+ region.update();
+ }
+
+ /** Generate a Hashcode for this object
+ * @return a string defining the hashcode
+ */
+ public String getTextHashCode(){
+ return "" + fontname.hashCode() + str.hashCode();
+ }
+
+ /** Render the Object based using the associated Region
+ * previously generated.
+ */
+ public void renderString3D() {
+ region.render(null, 0, 0, 0);
+ }
+ /** Render the Object based using the associated Region
+ * previously generated.
+ */
+ public void renderString3D(PMVMatrix matrix, int vp_width, int vp_height, int size) {
+ region.render(matrix, vp_width, vp_height, size);
+ }
+
+ /** Get the Origion of this GlyphString
+ * @return
+ */
+ public Vertex getOrigin() {
+ return origin;
+ }
+
+ /** Destroy the associated OGL objects
+ */
+ public void destroy(){
+ region.destroy();
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/font/FontConstructor.java b/src/jogl/classes/jogamp/graph/font/FontConstructor.java
new file mode 100644
index 000000000..a382d292e
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/FontConstructor.java
@@ -0,0 +1,34 @@
+/**
+ * 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 com.jogamp.graph.font.Font;
+
+public interface FontConstructor {
+ Font create(String name);
+}
diff --git a/src/jogl/classes/jogamp/graph/font/FontInt.java b/src/jogl/classes/jogamp/graph/font/FontInt.java
new file mode 100644
index 000000000..4d9390da2
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/FontInt.java
@@ -0,0 +1,50 @@
+/**
+ * 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 jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+
+public interface FontInt extends Font {
+
+ public interface Glyph extends Font.Glyph {
+ // reserved special glyph IDs
+ // http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#ba57949e
+ public static final int ID_UNKNOWN = 0;
+ public static final int ID_CR = 2;
+ public static final int ID_SPACE = 3;
+
+ public Path2D getPath(); // unscaled path
+ public Path2D getPath(float pixelSize);
+ }
+
+ public void getOutline(String string, float pixelSize,
+ AffineTransform transform, Path2D[] result);
+}
diff --git a/src/jogl/classes/jogamp/graph/font/JavaFontLoader.java b/src/jogl/classes/jogamp/graph/font/JavaFontLoader.java
new file mode 100644
index 000000000..33505e797
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/JavaFontLoader.java
@@ -0,0 +1,129 @@
+/**
+ * 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 com.jogamp.common.util.IntObjectHashMap;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontSet;
+import com.jogamp.graph.font.FontFactory;
+
+public class JavaFontLoader implements FontSet {
+
+ final static FontSet fontLoader = new JavaFontLoader();
+
+ public static FontSet get() {
+ return fontLoader;
+ }
+
+ final static String availableFontFileNames[] =
+ {
+ /* 00 */ "LucidaBrightRegular.ttf",
+ /* 01 */ "LucidaBrightItalic.ttf",
+ /* 02 */ "LucidaBrightDemiBold.ttf",
+ /* 03 */ "LucidaBrightDemiItalic.ttf",
+ /* 04 */ "LucidaSansRegular.ttf",
+ /* 05 */ "LucidaSansDemiBold.ttf",
+ /* 06 */ "LucidaTypewriterRegular.ttf",
+ /* 07 */ "LucidaTypewriterBold.ttf",
+ };
+
+ final String javaFontPath;
+
+ private JavaFontLoader() {
+ javaFontPath = System.getProperty("java.home") + "/lib/fonts/";
+ }
+
+ // FIXME: Add cache size to limit memory usage
+ static final IntObjectHashMap fontMap = new IntObjectHashMap();
+
+ static boolean is(int bits, int bit) {
+ return 0 != ( bits & bit ) ;
+ }
+
+ public Font getDefault() {
+ return get(FAMILY_REGULAR, 0) ; // Sans Serif Regular
+ }
+
+ public Font get(int family, int style) {
+ Font font = (Font)fontMap.get( ( family << 8 ) | style );
+ if (font != null) {
+ return font;
+ }
+
+ // 1st process Sans Serif (2 fonts)
+ if( is(style, STYLE_SERIF) ) {
+ if( is(style, STYLE_BOLD) ) {
+ font = abspath(availableFontFileNames[5], family, style);
+ } else {
+ font = abspath(availableFontFileNames[4], family, style);
+ }
+ fontMap.put( ( family << 8 ) | style, font );
+ return font;
+ }
+
+ // Serif Fonts ..
+ switch (family) {
+ case FAMILY_LIGHT:
+ case FAMILY_MEDIUM:
+ case FAMILY_CONDENSED:
+ case FAMILY_REGULAR:
+ if( is(style, STYLE_BOLD) ) {
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[3], family, style);
+ } else {
+ font = abspath(availableFontFileNames[2], family, style);
+ }
+ } else if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[1], family, style);
+ } else {
+ font = abspath(availableFontFileNames[0], family, style);
+ }
+ break;
+
+ case FAMILY_MONOSPACED:
+ if( is(style, STYLE_BOLD) ) {
+ font = abspath(availableFontFileNames[7], family, style);
+ } else {
+ font = abspath(availableFontFileNames[6], family, style);
+ }
+ break;
+ }
+
+ return font;
+ }
+
+ Font abspath(String fname, int family, int style) {
+ final Font f = FontFactory.getFontConstr().create(javaFontPath+fname);
+ if(null != f) {
+ fontMap.put( ( family << 8 ) | style, f );
+ }
+ return f;
+
+ }
+
+}
diff --git a/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java b/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java
new file mode 100644
index 000000000..e09ea85e5
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/UbuntuFontLoader.java
@@ -0,0 +1,132 @@
+/**
+ * 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 com.jogamp.common.util.IntObjectHashMap;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontSet;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.opengl.util.Locator;
+
+public class UbuntuFontLoader implements FontSet {
+
+ final static FontSet fontLoader = new UbuntuFontLoader();
+
+ public static FontSet get() {
+ return fontLoader;
+ }
+
+ final static String availableFontFileNames[] =
+ {
+ /* 00 */ "Ubuntu-R.ttf", // regular
+ /* 01 */ "Ubuntu-RI.ttf", // regular italic
+ /* 02 */ "Ubuntu-B.ttf", // bold
+ /* 03 */ "Ubuntu-BI.ttf", // bold italic
+ /* 04 */ "Ubuntu-L.ttf", // light
+ /* 05 */ "Ubuntu-LI.ttf", // light italic
+ /* 06 */ "Ubuntu-M.ttf", // medium
+ /* 07 */ "Ubuntu-MI.ttf", // medium italic
+
+ };
+
+ final static String relPath = "fonts/ubuntu/" ;
+
+ private UbuntuFontLoader() {
+ }
+
+ // FIXME: Add cache size to limit memory usage
+ static final IntObjectHashMap fontMap = new IntObjectHashMap();
+
+ static boolean is(int bits, int bit) {
+ return 0 != ( bits & bit ) ;
+ }
+
+ public Font getDefault() {
+ return get(FAMILY_REGULAR, 0) ; // Sans Serif Regular
+ }
+
+ public Font get(int family, int style)
+ {
+ Font font = (Font)fontMap.get( ( family << 8 ) | style );
+ if (font != null) {
+ return font;
+ }
+
+ switch (family) {
+ case FAMILY_MONOSPACED:
+ case FAMILY_CONDENSED:
+ case FAMILY_REGULAR:
+ if( is(style, STYLE_BOLD) ) {
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[3], family, style);
+ } else {
+ font = abspath(availableFontFileNames[2], family, style);
+ }
+ } else if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[1], family, style);
+ } else {
+ font = abspath(availableFontFileNames[0], family, style);
+ }
+ break;
+
+ case FAMILY_LIGHT:
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[5], family, style);
+ } else {
+ font = abspath(availableFontFileNames[4], family, style);
+ }
+ break;
+
+ case FAMILY_MEDIUM:
+ if( is(style, STYLE_ITALIC) ) {
+ font = abspath(availableFontFileNames[6], family, style);
+ } else {
+ font = abspath(availableFontFileNames[7], family, style);
+ }
+ break;
+ }
+
+ return font;
+ }
+
+ Font abspath(String fname) {
+ return FontFactory.getFontConstr().create(
+ Locator.getResource(UbuntuFontLoader.class, relPath+fname).getPath() );
+ }
+
+ Font abspath(String fname, int family, int style) {
+ final Font f = FontFactory.getFontConstr().create(
+ Locator.getResource(UbuntuFontLoader.class, relPath+fname).getPath() );
+ if(null != f) {
+ fontMap.put( ( family << 8 ) | style, f );
+ }
+ return f;
+ }
+
+
+}
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt
new file mode 100644
index 000000000..15bdc0c0b
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/CONTRIBUTING.txt
@@ -0,0 +1,21 @@
+The Ubuntu Font Family is very long-term endeavour, and the first time
+that a professionally-designed font has been funded specifically with
+the intent of being an on-going community expanded project:
+
+ http://font.ubuntu.com/
+
+Development of the Ubuntu Font Family is undertaken on Launchpad:
+
+ http://launchpad.net/ubuntu-font-family/
+
+and this is where milestones, bug management and releases are handled.
+
+Contributions are welcomed. Your work will be used on millions of
+computers every single day! Following the initial bootstrapping of
+Latin, Cyrillic, Greek, Arabic and Hebrew expansion will be undertaken
+by font designers from the font design and Ubuntu communities.
+
+To ensure that the Ubuntu Font Family can be re-licensed to future
+widely-used libre font licences, copyright assignment is being required:
+
+ https://launchpad.net/~uff-contributors
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt
new file mode 100644
index 000000000..cf0e4c111
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/FONTLOG.txt
@@ -0,0 +1,211 @@
+This is the FONTLOG file for the Ubuntu Font Family and attempts to follow
+the recommendations at: http://scripts.sil.org/OFL-FAQ_web#43cecb44
+
+
+Overview
+
+The new Ubuntu Font Family was started to enable the personality of
+Ubuntu to be seen and felt in every menu, button and dialog.
+The typeface is sans-serif, uses OpenType features and is manually
+hinted for clarity on desktop and mobile computing screens.
+
+The scope of the Ubuntu Font Family includes all the languages used by
+the various Ubuntu users around the world in tune with Ubuntu's
+philosophy which states that every user should be able to use their
+software in the language of their choice. So the Ubuntu Font Family
+project will be extended to cover many more written languages.
+
+
+History
+
+The Ubuntu Font Family has been creating during 2010. As of December 2010
+coverage is provided for Latin, Cyrillic and Greek across Regular, Italic,
+Bold and Bold-Italic.
+
+
+ChangeLog
+
+2010-03-08 (Paul Sladen) Ubuntu Font Family version 0.71.2
+
+ * (Production) Adjust Medium WeightClass to 500 (Md, MdIt) (LP: #730912)
+
+2010-03-07 (Paul Sladen) Ubuntu Font Family version 0.71.1
+
+ * (Design) Add Capitalised version of glyphs and kern. (Lt, LtIt,
+ Md, MdIt) DM (LP: #677446)
+ * (Design) Re-space and tighen Regular and Italic by amount specified
+ by Mark Shuttleworth (minus 4 FUnits). (Rg, It) (LP: #677149)
+ * (Design) Design: Latin (U+0192) made straight more like l/c f with
+ tail (LP: #670768)
+ * (Design) (U+01B3) should have hook on right, as the lowercase
+ (U+01B4) (LP: #681026)
+ * (Design) Tail of Light Italic germandbls, longs and lowercase 'f'
+ to match Italic/BoldItalic (LP: #623925)
+ * (Production) Update <case> feature (Lt, LtIt, Md, MdIt). DM
+ (LP: #676538, #676539)
+ * (Production) Remove Bulgarian locl feature for Italics. (LP: #708578)
+ * (Production) Update Description information with new string:
+ "The Ubuntu Font Family are libre fonts funded by Canonical Ltd
+ on behalf of the Ubuntu project. The font design work and
+ technical implementation is being undertaken by Dalton Maag. The
+ typeface is sans-serif, uses OpenType features and is manually
+ hinted for clarity on desktop and mobile computing screens. The
+ scope of the Ubuntu Font Family includes all the languages used
+ by the various Ubuntu users around the world in tune with
+ Ubuntu's philosophy which states that every user should be able
+ to use their software in the language of their choice. The
+ project is ongoing, and we expect the family will be extended to
+ cover many written languages in the coming years."
+ (Rg, It, Bd, BdIt, Lt, LtIt, Md, MdIt) (LP: #690590)
+ * (Production) Pixel per em indicator added at U+F000 (Lt, LtIt, Md,
+ MdIt) (LP: #615787)
+ * (Production) Version number indicator added at U+EFFD (Lt, LtIt, Md,
+ MdIt) (LP: #640623)
+ * (Production) fstype bit set to 0 - Editable (Lt, LtIt, Md, MdIt)
+ (LP: #648406)
+ * (Production) Localisation of name table has been removed because
+ of problems with Mac OS/X interpretation of localisation. DM
+ (LP: #730785)
+ * (Hinting) Regular '?' dot non-circular (has incorrect control
+ value). (LP: #654336)
+ * (Hinting) Too much space after latin capital 'G' in 13pt
+ regular. Now reduced. (LP: #683437)
+ * (Hinting) Balance Indian Rupee at 18,19pt (LP: #662177)
+ * (Hinting) Make Regular '£' less ambiguous at 13-15 ppm (LP: #685562)
+ * (Hinting) Regular capital 'W' made symmetrical at 31 ppem (LP: #686168)
+
+2010-12-14 (Paul Sladen) Ubuntu Font Family version 0.70.1
+
+ Packaging, rebuilt from '2010-12-08 UbuntuFontsSourceFiles_070.zip':
+ * (Midstream) Fstype bit != 0 (LP: #648406)
+ * (Midstream) Add unit test to validate fstype bits (LP: #648406)
+ * (Midstream) Add unit test to validate licence
+
+2010-12-14 (Paul Sladen) Ubuntu Font Family version 0.70
+
+ Release notes 0.70:
+ * (Design) Add Capitalised version of glyphs and kern. (Rg, It, Bd,
+ BdIt) DM (LP: #676538, #677446)
+ * (Design) Give acute and grave a slight upright move to more match
+ the Hungarian double acute angle. (Rg, It, Bd, BdIt) (LP: #656647)
+ * (Design) Shift Bold Italic accent glyphs to be consistent with the
+ Italic. (BdIt only) DM (LP: #677449)
+ * (Design) Check spacing and kerning of dcaron, lcaron and
+ tcaron. (Rg, It, Bd, BdIt) (LP: #664722)
+ * (Design) Add positive kerning to () {} [] to open out the
+ combinations so they are less like a closed box. (Rg, It, Bd,
+ BdIt) (LP: #671228)
+ * (Design) Change design of acute.asc and check highest points (Bd
+ and BdIt only) DM
+ * (Production) Update <case> feature. DM (LP: #676538, #676539)
+ * (Production) Remove Romanian locl feature. (Rg, It, Bd, BdIt)
+ (LP: #635615)
+ * (Production) Update Copyright information with new
+ strings. "Copyright 2010 Canonical Ltd. Licensed under the Ubuntu
+ Font Licence 1.0" Trademark string "Ubuntu and Canonical are
+ registered trademarks of Canonical Ltd." (Rg, It, Bd, BdIt) DM
+ (LP: #677450)
+ * (Design) Check aligning of hyphen, math signs em, en, check braces
+ and other brackets. 16/11 (LP: #676465)
+ * (Production) Pixel per em indicator added at U+F000 (Rg, It, Bd,
+ BdIt) (LP: #615787)
+ * (Production) Version number indicator added at U+EFFD (Rg, It, Bd,
+ BdIt) (LP: #640623)
+ * (Production) fstype bit set to 0 - Editable (Rg, It, Bd, BdIt)
+ (LP: #648406)
+
+2010-10-05 (Paul Sladen) Ubuntu Font Family version 0.69
+
+ [Dalton Maag]
+ * Italic,
+ - Hinting on lowercase Italic l amended 19ppm (LP: #632451)
+ - Hinting on lowercase Italic u amended 12ppm (LP: #626376)
+
+ * Regular, Italic, Bold, BoldItalic
+ - New Rupee Sign added @ U+20B9 (LP: #645987)
+ - Ubuntu Roundel added @ U+E0FF (LP: #651606)
+
+ [Paul Sladen]
+ * All
+ - Removed "!ubu" GSUB.calt ligature for U+E0FF (LP: #651606)
+
+
+Acknowledgements
+
+If you make modifications be sure to add your name (N), email (E),
+web-address (if you have one) (W) and description (D). This list is in
+alphabetical order.
+
+N: Amélie Bonet
+W: http://ameliebonet.com/
+D: Type design with Dalton Maag, particularly Ubuntu Mono
+
+N: Ron Carpenter
+N: Vincent Connare
+N: Lukas Paltram
+W: http://www.daltonmaag.com/
+D: Type design and engineering with Dalton Maag
+
+N: Dave Crossland
+E: dave@understandingfonts.com
+W: http://understandingfonts.com/
+D: Documentation and libre licensing guidance
+
+N: Iain Farrell
+W: http://www.flickr.com/photos/iain
+D: Ubuntu Font Family delivery for the Ubuntu UX team
+
+N: Shiraaz Gabru
+W: http://www.daltonmaag.com/
+D: Ubuntu Font Family project management at Dalton Maag
+
+N: Marcus Haslam
+W: http://design.canonical.com/author/marcus-haslam/
+D: Creative inspiration
+
+N: Ben Laenen
+D: Inspiration behind the pixels-per-em (PPEM) readout debugging glyph at U+F000
+ (for this font the concept was re-implemented from scratch by Dalton-Maag)
+
+N: Bruno Maag
+W: http://www.daltonmaag.com/
+D: Stylistic direction of the Ubuntu Font Family, as head of Dalton Maag
+
+N: Ivanka Majic
+W: http://www.ivankamajic.com/
+D: Guiding the UX team and Cyrillic feedback
+
+N: David Marshall
+N: Malcolm Wooden
+W: http://www.daltonmaag.com/
+D: Font Engineering and technical direction
+
+N: Rodrigo Rivas
+D: Indian Rupee Sign glyph
+
+N: Mark Shuttleworth
+E: mark@ubuntu.com
+W: http://www.markshuttleworth.com/
+D: Executive quality-control and funding
+
+N: Paul Sladen
+E: ubuntu@paul.sladen.org
+W: http://www.paul.sladen.org/
+D: Bug triaging, packaging
+
+N: Nicolas Spalinger
+W: http://planet.open-fonts.org
+D: Continuous guidance on libre/open font licensing, best practises in source
+ tree layout, release and packaging (pkg-fonts Debian team)
+
+N: Kenneth Wimer
+D: Initial PPA packaging
+
+* Canonical Ltd is the primary commercial sponsor of the Ubuntu and
+ Kubuntu operating systems
+* Dalton Maag are a custom type foundry headed by Bruno Maag
+
+For further documentation, information on contributors, source code
+downloads and those involved with the Ubuntu Font Family, visit:
+
+ http://font.ubuntu.com/
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt
new file mode 100644
index 000000000..776a25edf
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE-FAQ.txt
@@ -0,0 +1,177 @@
+ Ubuntu Font Family Licensing FAQ
+
+ Stylistic Foundations
+
+ The Ubuntu Font Family is the first time that a libre typeface has been
+ designed professionally and explicitly with the intent of developing a
+ public and long-term community-based development process.
+
+ When developing an open project, it is generally necessary to have firm
+ foundations: a font needs to maintain harmony within itself even across
+ many type designers and writing systems. For the [1]Ubuntu Font Family,
+ the process has been guided with the type foundry Dalton Maag setting
+ the project up with firm stylistic foundation covering several
+ left-to-right scripts: Latin, Greek and Cyrillic; and right-to-left
+ scripts: Arabic and Hebrew (due in 2011).
+
+ With this starting point the community will, under the supervision of
+ [2]Canonical and [3]Dalton Maag, be able to build on the existing font
+ sources to expand their character coverage. Ultimately everybody will
+ be able to use the Ubuntu Font Family in their own written languages
+ across the whole of Unicode (and this will take some time!).
+
+ Licensing
+
+ The licence chosen by any free software project is one of the
+ foundational decisions that sets out how derivatives and contributions
+ can occur, and in turn what kind of community will form around the
+ project.
+
+ Using a licence that is compatible with other popular licences is a
+ powerful constraint because of the [4]network effects: the freedom to
+ share improvements between projects allows free software to reach
+ high-quality over time. Licence-proliferation leads to many
+ incompatible licences, undermining the network effect, the freedom to
+ share and ultimately making the libre movement that Ubuntu is a part of
+ less effective. For all kinds of software, writing a new licence is not
+ to be taken lightly and is a choice that needs to be thoroughly
+ justified if this path is taken.
+
+ Today it is not clear to Canonical what the best licence for a font
+ project like the Ubuntu Font Family is: one that starts life designed
+ by professionals and continues with the full range of community
+ development, from highly commercial work in new directions to curious
+ beginners' experimental contributions. The fast and steady pace of the
+ Ubuntu release cycle means that an interim libre licence has been
+ necessary to enable the consideration of the font family as part of
+ Ubuntu 10.10 operating system release.
+
+ Before taking any decision on licensing, Canonical as sponsor and
+ backer of the project has reviewed the many existing licenses used for
+ libre/open fonts and engaged the stewards of the most popular licenses
+ in detailed discussions. The current interim licence is the first step
+ in progressing the state-of-the-art in licensing for libre/open font
+ development.
+
+ The public discussion must now involve everyone in the (comparatively
+ new) area of the libre/open font community; including font users,
+ software freedom advocates, open source supporters and existing libre
+ font developers. Most importantly, the minds and wishes of professional
+ type designers considering entering the free software business
+ community must be taken on board.
+
+ Conversations and discussion has taken place, privately, with
+ individuals from the following groups (generally speaking personally on
+ behalf of themselves, rather than their affiliations):
+ * [5]SIL International
+ * [6]Open Font Library
+ * [7]Software Freedom Law Center
+ * [8]Google Font API
+
+ Document embedding
+
+ One issue highlighted early on in the survey of existing font licences
+ is that of document embedding. Almost all font licences, both free and
+ unfree, permit embedding a font into a document to a certain degree.
+ Embedding a font with other works that make up a document creates a
+ "combined work" and copyleft would normally require the whole document
+ to be distributed under the terms of the font licence. As beautiful as
+ the font might be, such a licence makes a font too restrictive for
+ useful general purpose digital publishing.
+
+ The situation is not entirely unique to fonts and is encountered also
+ with tools such as GNU Bison: a vanilla GNU GPL licence would require
+ anything generated with Bison to be made available under the terms of
+ the GPL as well. To avoid this, Bison is [9]published with an
+ additional permission to the GPL which allows the output of Bison to be
+ made available under any licence.
+
+ The conflict between licensing of fonts and licensing of documents, is
+ addressed in two popular libre font licences, the SIL OFL and GNU GPL:
+ * [10]SIL Open Font Licence: When OFL fonts are embedded in a
+ document, the OFL's terms do not apply to that document. (See
+ [11]OFL-FAQ for details.
+ * [12]GPL Font Exception: The situation is resolved by granting an
+ additional permission to allow documents to not be covered by the
+ GPL. (The exception is being reviewed).
+
+ The Ubuntu Font Family must also resolve this conflict, ensuring that
+ if the font is embedded and then extracted it is once again clearly
+ under the terms of its libre licence.
+
+ Long-term licensing
+
+ Those individuals involved, especially from Ubuntu and Canonical, are
+ interested in finding a long-term libre licence that finds broad favour
+ across the whole libre/open font community. The deliberation during the
+ past months has been on how to licence the Ubuntu Font Family in the
+ short-term, while knowingly encouraging everyone to pursue a long-term
+ goal.
+ * [13]Copyright assignment will be required so that the Ubuntu Font
+ Family's licensing can be progressively expanded to one (or more)
+ licences, as best practice continues to evolve within the
+ libre/open font community.
+ * Canonical will support and fund legal work on libre font licensing.
+ It is recognised that the cost and time commitments required are
+ likely to be significant. We invite other capable parties to join
+ in supporting this activity.
+
+ The GPL version 3 (GPLv3) will be used for Ubuntu Font Family build
+ scripts and the CC-BY-SA for associated documentation and non-font
+ content: all items which do not end up embedded in general works and
+ documents.
+
+Ubuntu Font Licence
+
+ For the short-term only, the initial licence is the [14]Ubuntu Font
+ License (UFL). This is loosely inspired from the work on the SIL
+ OFL 1.1, and seeks to clarify the issues that arose during discussions
+ and legal review, from the perspective of the backers, Canonical Ltd.
+ Those already using established licensing models such as the GPL, OFL
+ or Creative Commons licensing should have no worries about continuing
+ to use them. The Ubuntu Font Licence (UFL) and the SIL Open Font
+ Licence (SIL OFL) are not identical and should not be confused with
+ each other. Please read the terms precisely. The UFL is only intended
+ as an interim license, and the overriding aim is to support the
+ creation of a more suitable and generic libre font licence. As soon as
+ such a licence is developed, the Ubuntu Font Family will migrate to
+ it—made possible by copyright assignment in the interium. Between the
+ OFL 1.1, and the UFL 1.0, the following changes are made to produce the
+ Ubuntu Font Licence:
+ * Clarification:
+
+ 1. Document embedding (see [15]embedding section above).
+ 2. Apply at point of distribution, instead of receipt
+ 3. Author vs. copyright holder disambiguation (type designers are
+ authors, with the copyright holder normally being the funder)
+ 4. Define "Propagate" (for internationalisation, similar to the GPLv3)
+ 5. Define "Substantially Changed"
+ 6. Trademarks are explicitly not transferred
+ 7. Refine renaming requirement
+
+ Streamlining:
+ 8. Remove "not to be sold separately" clause
+ 9. Remove "Reserved Font Name(s)" declaration
+
+ A visual demonstration of how these points were implemented can be
+ found in the accompanying coloured diff between SIL OFL 1.1 and the
+ Ubuntu Font Licence 1.0: [16]ofl-1.1-ufl-1.0.diff.html
+
+References
+
+ 1. http://font.ubuntu.com/
+ 2. http://www.canonical.com/
+ 3. http://www.daltonmaag.com/
+ 4. http://en.wikipedia.org/wiki/Network_effect
+ 5. http://scripts.sil.org/
+ 6. http://openfontlibrary.org/
+ 7. http://www.softwarefreedom.org/
+ 8. http://code.google.com/webfonts
+ 9. http://www.gnu.org/licenses/gpl-faq.html#CanIUseGPLToolsForNF
+ 10. http://scripts.sil.org/OFL_web
+ 11. http://scripts.sil.org/OFL-FAQ_web
+ 12. http://www.gnu.org/licenses/gpl-faq.html#FontException
+ 13. https://launchpad.net/~uff-contributors
+ 14. http://font.ubuntu.com/ufl/ubuntu-font-licence-1.0.txt
+ 15. http://font.ubuntu.com/ufl/FAQ.html#embedding
+ 16. http://font.ubuntu.com/ufl/ofl-1.1-ufl-1.0.diff.html
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE.txt
new file mode 100644
index 000000000..ae78a8f94
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/LICENCE.txt
@@ -0,0 +1,96 @@
+-------------------------------
+UBUNTU FONT LICENCE Version 1.0
+-------------------------------
+
+PREAMBLE
+This licence allows the licensed fonts to be used, studied, modified and
+redistributed freely. The fonts, including any derivative works, can be
+bundled, embedded, and redistributed provided the terms of this licence
+are met. The fonts and derivatives, however, cannot be released under
+any other licence. The requirement for fonts to remain under this
+licence does not require any document created using the fonts or their
+derivatives to be published under this licence, as long as the primary
+purpose of the document is not to be a vehicle for the distribution of
+the fonts.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this licence and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Original Version" refers to the collection of Font Software components
+as received under this licence.
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to
+a new environment.
+
+"Copyright Holder(s)" refers to all individuals and companies who have a
+copyright ownership of the Font Software.
+
+"Substantially Changed" refers to Modified Versions which can be easily
+identified as dissimilar to the Font Software by users of the Font
+Software comparing the Original Version with the Modified Version.
+
+To "Propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification and with or without charging
+a redistribution fee), making available to the public, and in some
+countries other activities as well.
+
+PERMISSION & CONDITIONS
+This licence does not grant any rights under trademark law and all such
+rights are reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of the Font Software, to propagate the Font Software, subject to
+the below conditions:
+
+1) Each copy of the Font Software must contain the above copyright
+notice and this licence. These can be included either as stand-alone
+text files, human-readable headers or in the appropriate machine-
+readable metadata fields within text or binary files as long as those
+fields can be easily viewed by the user.
+
+2) The font name complies with the following:
+(a) The Original Version must retain its name, unmodified.
+(b) Modified Versions which are Substantially Changed must be renamed to
+avoid use of the name of the Original Version or similar names entirely.
+(c) Modified Versions which are not Substantially Changed must be
+renamed to both (i) retain the name of the Original Version and (ii) add
+additional naming elements to distinguish the Modified Version from the
+Original Version. The name of such Modified Versions must be the name of
+the Original Version, with "derivative X" where X represents the name of
+the new work, appended to that name.
+
+3) The name(s) of the Copyright Holder(s) and any contributor to the
+Font Software shall not be used to promote, endorse or advertise any
+Modified Version, except (i) as required by this licence, (ii) to
+acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with
+their explicit written permission.
+
+4) The Font Software, modified or unmodified, in part or in whole, must
+be distributed entirely under this licence, and must not be distributed
+under any other licence. The requirement for fonts to remain under this
+licence does not affect any document created using the Font Software,
+except any version of the Font Software extracted from a document
+created using the Font Software may only be distributed under this
+licence.
+
+TERMINATION
+This licence becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
+DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/README.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/README.txt
new file mode 100644
index 000000000..292d4ade6
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/README.txt
@@ -0,0 +1,15 @@
+ ----------------------
+ Ubuntu Font Family
+ ======================
+
+The Ubuntu Font Family are a set of matching new libre/open fonts in
+development during 2010--2011. The development is being funded by
+Canonical Ltd on behalf the wider Free Software community and the
+Ubuntu project. The technical font design work and implementation is
+being undertaken by Dalton Maag.
+
+Both the final font Truetype/OpenType files and the design files used
+to produce the font family are distributed under an open licence and
+you are expressly encouraged to experiment, modify, share and improve.
+
+ http://font.ubuntu.com/
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt
new file mode 100644
index 000000000..d34265bc8
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/TRADEMARKS.txt
@@ -0,0 +1,4 @@
+Ubuntu and Canonical are registered trademarks of Canonical Ltd.
+
+The licence accompanying these works does not grant any rights
+under trademark law and all such rights are reserved.
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttf
new file mode 100644
index 000000000..7639344e7
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-B.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttf
new file mode 100644
index 000000000..337b8a88b
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-BI.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttf
new file mode 100644
index 000000000..c3b0fa46d
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-L.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttf
new file mode 100644
index 000000000..d65e8eab3
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-LI.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttf
new file mode 100644
index 000000000..387ef03fc
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-M.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttf
new file mode 100644
index 000000000..5b92fcb5d
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-MI.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf
new file mode 100644
index 000000000..a46446440
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-R.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttf b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttf
new file mode 100644
index 000000000..0e0955918
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/Ubuntu-RI.ttf
Binary files differ
diff --git a/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/copyright.txt b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/copyright.txt
new file mode 100644
index 000000000..3a45d712e
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/fonts/ubuntu/copyright.txt
@@ -0,0 +1,5 @@
+Copyright 2010 Canonical Ltd.
+
+This Font Software is licensed under the Ubuntu Font Licence, Version
+1.0. https://launchpad.net/ubuntu-font-licence
+
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
new file mode 100644
index 000000000..0d018a314
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java
@@ -0,0 +1,268 @@
+/**
+ * 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 jogamp.graph.font.FontInt;
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+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.CmapIndexEntry;
+import net.java.dev.typecast.ot.table.CmapTable;
+import net.java.dev.typecast.ot.table.HdmxTable;
+import net.java.dev.typecast.ot.table.ID;
+
+import com.jogamp.common.util.IntObjectHashMap;
+import com.jogamp.graph.geom.AABBox;
+
+class TypecastFont implements FontInt {
+ static final boolean DEBUG = false;
+
+ final OTFontCollection fontset;
+ final OTFont font;
+ TypecastHMetrics metrics;
+ final CmapFormat cmapFormat;
+ int cmapentries;
+
+ // FIXME: Add cache size to limit memory usage ??
+ IntObjectHashMap char2Glyph;
+
+ public TypecastFont(OTFontCollection fontset) {
+ this.fontset = fontset;
+ this.font = fontset.getFont(0);
+
+ // FIXME: Generic attempt to find the best CmapTable,
+ // which is assumed to be the one with the most entries (stupid 'eh?)
+ CmapTable cmapTable = font.getCmapTable();
+ CmapFormat[] _cmapFormatP = { null, null, null, null };
+ int platform = -1;
+ int platformLength = -1;
+ int encoding = -1;
+ for(int i=0; i<cmapTable.getNumTables(); i++) {
+ CmapIndexEntry cmapIdxEntry = cmapTable.getCmapIndexEntry(i);
+ int pidx = cmapIdxEntry.getPlatformId();
+ CmapFormat cf = cmapIdxEntry.getFormat();
+ if(DEBUG) {
+ System.err.println("CmapFormat["+i+"]: platform " + pidx +
+ ", encoding "+cmapIdxEntry.getEncodingId() + ": "+cf);
+ }
+ if( _cmapFormatP[pidx] == null ||
+ _cmapFormatP[pidx].getLength() < cf.getLength() ) {
+ _cmapFormatP[pidx] = cf;
+ if( cf.getLength() > platformLength ) {
+ platformLength = cf.getLength() ;
+ platform = pidx;
+ encoding = cmapIdxEntry.getEncodingId();
+ }
+ }
+ }
+ if(0 <= platform) {
+ cmapFormat = _cmapFormatP[platform];
+ if(DEBUG) {
+ System.err.println("Selected CmapFormat: platform " + platform +
+ ", encoding "+encoding + ": "+cmapFormat);
+ }
+ } else {
+ CmapFormat _cmapFormat = null;
+ /*if(null == _cmapFormat) {
+ platform = ID.platformMacintosh;
+ encoding = ID.encodingASCII;
+ _cmapFormat = cmapTable.getCmapFormat(platform, encoding);
+ } */
+ if(null == _cmapFormat) {
+ // default unicode
+ platform = ID.platformMicrosoft;
+ encoding = ID.encodingUnicode;
+ _cmapFormat = cmapTable.getCmapFormat((short)platform, (short)encoding);
+ }
+ if(null == _cmapFormat) {
+ // maybe a symbol font ?
+ platform = ID.platformMicrosoft;
+ encoding = ID.encodingSymbol;
+ _cmapFormat = cmapTable.getCmapFormat((short)platform, (short)encoding);
+ }
+ if(null == _cmapFormat) {
+ throw new RuntimeException("Cannot find a suitable cmap table for font "+font);
+ }
+ cmapFormat = _cmapFormat;
+ if(DEBUG) {
+ System.err.println("Selected CmapFormat (2): platform " + platform + ", encoding "+encoding + ": "+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);
+ System.err.println("num cmap ranges: "+cmapFormat.getRangeCount());
+
+ 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);
+ if(code < 15) {
+ System.err.println(" char: " + (int)j + " ( " + (char)j +" ) -> " + code);
+ }
+ }
+ }
+ }
+ char2Glyph = new IntObjectHashMap(cmapentries + cmapentries/4);
+ }
+
+ public String getName() {
+ return fontset.getFileName();
+ }
+
+ public Metrics getMetrics() {
+ if (metrics == null) {
+ metrics = new TypecastHMetrics(this);
+ }
+ return metrics;
+ }
+
+ public Glyph getGlyph(char symbol) {
+ TypecastGlyph result = (TypecastGlyph) char2Glyph.get(symbol);
+ if (null == result) {
+ // final short code = (short) char2Code.get(symbol);
+ short code = (short) cmapFormat.mapCharCode(symbol);
+ if(0 == code && 0 != symbol) {
+ // reserved special glyph IDs by convention
+ switch(symbol) {
+ case ' ': code = Glyph.ID_SPACE; break;
+ case '\n': code = Glyph.ID_CR; break;
+ default: code = Glyph.ID_UNKNOWN;
+ }
+ }
+
+ net.java.dev.typecast.ot.OTGlyph glyph = font.getGlyph(code);
+ if(null == glyph) {
+ glyph = font.getGlyph(Glyph.ID_UNKNOWN);
+ }
+ 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);
+ if(DEBUG) {
+ System.err.println("New glyph: " + (int)symbol + " ( " + (char)symbol +" ) -> " + code + ", contours " + glyph.getPointCount() + ": " + path);
+ }
+ final HdmxTable hdmx = font.getHdmxTable();
+ if (null!= result && null != hdmx) {
+ /*if(DEBUG) {
+ System.err.println("hdmx "+hdmx);
+ }*/
+ for (int i=0; i<hdmx.getNumberOfRecords(); i++)
+ {
+ final HdmxTable.DeviceRecord dr = hdmx.getRecord(i);
+ result.addAdvance(dr.getWidth(code), dr.getPixelSize());
+ if(DEBUG) {
+ System.err.println("hdmx advance : pixelsize = "+dr.getWidth(code)+" : "+ dr.getPixelSize());
+ }
+ }
+ }
+ char2Glyph.put(symbol, result);
+ }
+ return result;
+ }
+
+ public void getOutline(String string, float pixelSize, AffineTransform transform, Path2D[] result) {
+ TypecastRenderer.getOutline(this, string, pixelSize, transform, result);
+ }
+
+ public float getStringWidth(String string, float pixelSize) {
+ float width = 0;
+ final int len = string.length();
+ for (int i=0; i< len; i++)
+ {
+ char character = string.charAt(i);
+ if (character == '\n') {
+ width = 0;
+ } else {
+ Glyph glyph = getGlyph(character);
+ width += glyph.getAdvance(pixelSize, false);
+ }
+ }
+
+ return (int)(width + 0.5f);
+ }
+
+ public float getStringHeight(String 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);
+ height = (int)Math.ceil(Math.max(bbox.getHeight(), height));
+ }
+ }
+ return height;
+ }
+
+ public AABBox getStringBounds(CharSequence string, float pixelSize) {
+ 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;
+ float totalHeight = 0;
+ float totalWidth = 0;
+ float curLineWidth = 0;
+ for (int i=0; i<string.length(); i++) {
+ char character = string.charAt(i);
+ if (character == '\n') {
+ totalWidth = Math.max(curLineWidth, totalWidth);
+ curLineWidth = 0;
+ totalHeight -= advanceY;
+ continue;
+ }
+ Glyph glyph = getGlyph(character);
+ curLineWidth += glyph.getAdvance(pixelSize, true);
+ }
+ if (curLineWidth > 0) {
+ totalHeight -= advanceY;
+ totalWidth = Math.max(curLineWidth, totalWidth);
+ }
+ return new AABBox(0, 0, 0, totalWidth, totalHeight,0);
+ }
+
+ final public int getNumGlyphs() {
+ return font.getNumGlyphs();
+ }
+} \ No newline at end of file
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java
new file mode 100644
index 000000000..5fb9d32f7
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastFontConstructor.java
@@ -0,0 +1,53 @@
+/**
+ * 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.FontConstructor;
+
+import net.java.dev.typecast.ot.OTFontCollection;
+
+import com.jogamp.graph.font.Font;
+
+
+public class TypecastFontConstructor implements FontConstructor {
+
+ public Font create(String path) {
+ OTFontCollection fontset;
+ try {
+ fontset = OTFontCollection.create(new File(path));
+ return new TypecastFont(fontset);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+} \ No newline at end of file
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
new file mode 100644
index 000000000..88d865f9c
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java
@@ -0,0 +1,232 @@
+/**
+ * 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 jogamp.graph.font.FontInt;
+import jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.AABBox;
+
+public class TypecastGlyph implements FontInt.Glyph {
+ public class Advance
+ {
+ final Font font;
+ final float advance;
+ HashMap<Float, Float> size2advance = new HashMap<Float, Float>();
+
+ public Advance(Font font, float advance)
+ {
+ this.font = font;
+ this.advance = advance;
+ }
+
+ public void reset() {
+ size2advance.clear();
+ }
+
+ public float getScale(float pixelSize)
+ {
+ return this.font.getMetrics().getScale(pixelSize);
+ }
+
+ public void add(float advance, float size)
+ {
+ size2advance.put(size, advance);
+ }
+
+ public float get(float size, boolean useFrationalMetrics)
+ {
+ Float fo = size2advance.get(size);
+ if(null == fo) {
+ float value = (this.advance * getScale(size));
+ if (useFrationalMetrics == false) {
+ //value = (float)Math.ceil(value);
+ // value = (int)value;
+ value = (int) ( value + 0.5f ) ; // TODO: check
+ }
+ size2advance.put(size, value);
+ return value;
+ }
+ return fo.floatValue();
+ }
+
+ public String toString()
+ {
+ return "\nAdvance:"+
+ "\n advance: "+this.advance+
+ "\n advances: \n"+size2advance;
+ }
+ }
+
+ public class Metrics
+ {
+ AABBox bbox;
+ Advance advance;
+
+ public Metrics(Font font, AABBox bbox, float advance)
+ {
+ this.bbox = bbox;
+ this.advance = new Advance(font, advance);
+ }
+
+ public void reset() {
+ advance.reset();
+ }
+
+ public float getScale(float pixelSize)
+ {
+ return this.advance.getScale(pixelSize);
+ }
+
+ public AABBox getBBox()
+ {
+ return this.bbox;
+ }
+
+ public void addAdvance(float advance, float size)
+ {
+ this.advance.add(advance, size);
+ }
+
+ public float getAdvance(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 void reset(Path2D path) {
+ this.path = path;
+ this.metrics.reset();
+ }
+
+ 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 getScale(float pixelSize) {
+ return this.metrics.getScale(pixelSize);
+ }
+
+ public AABBox getBBox(float pixelSize) {
+ final float size = getScale(pixelSize);
+ AABBox newBox = getBBox().clone();
+ newBox.scale(size);
+ return newBox;
+ }
+
+ protected void addAdvance(float advance, float size) {
+ this.metrics.addAdvance(advance, size);
+ }
+
+ public float getAdvance(float pixelSize, boolean useFrationalMetrics) {
+ return this.metrics.getAdvance(pixelSize, useFrationalMetrics);
+ }
+
+ public Path2D getPath() {
+ return this.path;
+ }
+
+ 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;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java
new file mode 100644
index 000000000..cd8595498
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastHMetrics.java
@@ -0,0 +1,83 @@
+/**
+ * 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 TypecastHMetrics implements Metrics {
+ private final TypecastFont fontImpl;
+
+ // HeadTable
+ private final HeadTable headTable;
+ private final float unitsPerEM_Inv;
+ private final AABBox bbox;
+ // HheaTable
+ private final HheaTable hheaTable;
+ // VheaTable (for horizontal fonts)
+ // private final VheaTable vheaTable;
+
+ public TypecastHMetrics(TypecastFont fontImpl) {
+ this.fontImpl = fontImpl;
+ headTable = this.fontImpl.font.getHeadTable();
+ hheaTable = this.fontImpl.font.getHheaTable();
+ // vheaTable = this.fontImpl.font.getVheaTable();
+ unitsPerEM_Inv = 1.0f / ( (float) headTable.getUnitsPerEm() );
+
+ 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 = new AABBox(lowx, lowy, 0, highx, highy, 0); // invert
+ }
+
+ public final float getAscent(float pixelSize) {
+ return getScale(pixelSize) * -hheaTable.getAscender(); // invert
+ }
+ public final float getDescent(float pixelSize) {
+ return getScale(pixelSize) * -hheaTable.getDescender(); // invert
+ }
+ public final float getLineGap(float pixelSize) {
+ return getScale(pixelSize) * -hheaTable.getLineGap(); // invert
+ }
+ public final float getMaxExtend(float pixelSize) {
+ return getScale(pixelSize) * hheaTable.getXMaxExtent();
+ }
+ public final float getScale(float pixelSize) {
+ return pixelSize * unitsPerEM_Inv;
+ }
+ public final AABBox getBBox(float pixelSize) {
+ AABBox res = new AABBox(bbox.getLow(), bbox.getHigh());
+ res.scale(getScale(pixelSize));
+ 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
new file mode 100644
index 000000000..410f5b73a
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java
@@ -0,0 +1,163 @@
+/**
+ * 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 jogamp.graph.geom.plane.AffineTransform;
+import jogamp.graph.geom.plane.Path2D;
+
+import com.jogamp.graph.font.Font;
+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(TypecastFont font,
+ String 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.font.getHmtxTable().getAdvanceWidth(TypecastGlyph.ID_SPACE) * metrics.getScale(pixelSize);
+ continue;
+ }
+ TypecastGlyph glyph = (TypecastGlyph) font.getGlyph(character);
+ Path2D gp = 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);
+ }
+ }
+
+ /**
+ * 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;
+ }
+}
diff --git a/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java b/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java
new file mode 100644
index 000000000..2ba9f8d06
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/geom/plane/AffineTransform.java
@@ -0,0 +1,580 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import jogamp.graph.math.MathFloat;
+import org.apache.harmony.misc.HashCode;
+
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.Vertex.Factory;
+
+public class AffineTransform implements Cloneable, Serializable {
+
+ private static final long serialVersionUID = 1330973210523860834L;
+
+ static final String determinantIsZero = "Determinant is zero";
+
+ public static final int TYPE_IDENTITY = 0;
+ public static final int TYPE_TRANSLATION = 1;
+ public static final int TYPE_UNIFORM_SCALE = 2;
+ public static final int TYPE_GENERAL_SCALE = 4;
+ public static final int TYPE_QUADRANT_ROTATION = 8;
+ public static final int TYPE_GENERAL_ROTATION = 16;
+ public static final int TYPE_GENERAL_TRANSFORM = 32;
+ public static final int TYPE_FLIP = 64;
+ public static final int TYPE_MASK_SCALE = TYPE_UNIFORM_SCALE | TYPE_GENERAL_SCALE;
+ public static final int TYPE_MASK_ROTATION = TYPE_QUADRANT_ROTATION | TYPE_GENERAL_ROTATION;
+
+ /**
+ * The <code>TYPE_UNKNOWN</code> is an initial type value
+ */
+ static final int TYPE_UNKNOWN = -1;
+
+ /**
+ * The min value equivalent to zero. If absolute value less then ZERO it considered as zero.
+ */
+ static final float ZERO = (float) 1E-10;
+
+ private final Vertex.Factory<? extends Vertex> pointFactory;
+
+ /**
+ * The values of transformation matrix
+ */
+ float m00;
+ float m10;
+ float m01;
+ float m11;
+ float m02;
+ float m12;
+
+ /**
+ * The transformation <code>type</code>
+ */
+ transient int type;
+
+ public AffineTransform() {
+ pointFactory = null;
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0f;
+ m10 = m01 = m02 = m12 = 0.0f;
+ }
+
+ public AffineTransform(Factory<? extends Vertex> factory) {
+ pointFactory = factory;
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0f;
+ m10 = m01 = m02 = m12 = 0.0f;
+ }
+
+ public AffineTransform(AffineTransform t) {
+ this.pointFactory = t.pointFactory;
+ this.type = t.type;
+ this.m00 = t.m00;
+ this.m10 = t.m10;
+ this.m01 = t.m01;
+ this.m11 = t.m11;
+ this.m02 = t.m02;
+ this.m12 = t.m12;
+ }
+
+ public AffineTransform(Vertex.Factory<? extends Vertex> factory, float m00, float m10, float m01, float m11, float m02, float m12) {
+ pointFactory = factory;
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ public AffineTransform(Vertex.Factory<? extends Vertex> factory, float[] matrix) {
+ pointFactory = factory;
+ this.type = TYPE_UNKNOWN;
+ m00 = matrix[0];
+ m10 = matrix[1];
+ m01 = matrix[2];
+ m11 = matrix[3];
+ if (matrix.length > 4) {
+ m02 = matrix[4];
+ m12 = matrix[5];
+ }
+ }
+
+ /*
+ * Method returns type of affine transformation.
+ *
+ * Transform matrix is
+ * m00 m01 m02
+ * m10 m11 m12
+ *
+ * According analytic geometry new basis vectors are (m00, m01) and (m10, m11),
+ * translation vector is (m02, m12). Original basis vectors are (1, 0) and (0, 1).
+ * Type transformations classification:
+ * TYPE_IDENTITY - new basis equals original one and zero translation
+ * TYPE_TRANSLATION - translation vector isn't zero
+ * TYPE_UNIFORM_SCALE - vectors length of new basis equals
+ * TYPE_GENERAL_SCALE - vectors length of new basis doesn't equal
+ * TYPE_FLIP - new basis vector orientation differ from original one
+ * TYPE_QUADRANT_ROTATION - new basis is rotated by 90, 180, 270, or 360 degrees
+ * TYPE_GENERAL_ROTATION - new basis is rotated by arbitrary angle
+ * TYPE_GENERAL_TRANSFORM - transformation can't be inversed
+ */
+ public int getType() {
+ if (type != TYPE_UNKNOWN) {
+ return type;
+ }
+
+ int type = 0;
+
+ if (m00 * m01 + m10 * m11 != 0.0) {
+ type |= TYPE_GENERAL_TRANSFORM;
+ return type;
+ }
+
+ if (m02 != 0.0 || m12 != 0.0) {
+ type |= TYPE_TRANSLATION;
+ } else
+ if (m00 == 1.0 && m11 == 1.0 && m01 == 0.0 && m10 == 0.0) {
+ type = TYPE_IDENTITY;
+ return type;
+ }
+
+ if (m00 * m11 - m01 * m10 < 0.0) {
+ type |= TYPE_FLIP;
+ }
+
+ float dx = m00 * m00 + m10 * m10;
+ float dy = m01 * m01 + m11 * m11;
+ if (dx != dy) {
+ type |= TYPE_GENERAL_SCALE;
+ } else
+ if (dx != 1.0) {
+ type |= TYPE_UNIFORM_SCALE;
+ }
+
+ if ((m00 == 0.0 && m11 == 0.0) ||
+ (m10 == 0.0 && m01 == 0.0 && (m00 < 0.0 || m11 < 0.0)))
+ {
+ type |= TYPE_QUADRANT_ROTATION;
+ } else
+ if (m01 != 0.0 || m10 != 0.0) {
+ type |= TYPE_GENERAL_ROTATION;
+ }
+
+ return type;
+ }
+
+ public float getScaleX() {
+ return m00;
+ }
+
+ public float getScaleY() {
+ return m11;
+ }
+
+ public float getShearX() {
+ return m01;
+ }
+
+ public float getShearY() {
+ return m10;
+ }
+
+ public float getTranslateX() {
+ return m02;
+ }
+
+ public float getTranslateY() {
+ return m12;
+ }
+
+ public boolean isIdentity() {
+ return getType() == TYPE_IDENTITY;
+ }
+
+ public void getMatrix(float[] matrix) {
+ matrix[0] = m00;
+ matrix[1] = m10;
+ matrix[2] = m01;
+ matrix[3] = m11;
+ if (matrix.length > 4) {
+ matrix[4] = m02;
+ matrix[5] = m12;
+ }
+ }
+
+ public float getDeterminant() {
+ return m00 * m11 - m01 * m10;
+ }
+
+ public void setTransform(float m00, float m10, float m01, float m11, float m02, float m12) {
+ this.type = TYPE_UNKNOWN;
+ this.m00 = m00;
+ this.m10 = m10;
+ this.m01 = m01;
+ this.m11 = m11;
+ this.m02 = m02;
+ this.m12 = m12;
+ }
+
+ public void setTransform(AffineTransform t) {
+ type = t.type;
+ setTransform(t.m00, t.m10, t.m01, t.m11, t.m02, t.m12);
+ }
+
+ public void setToIdentity() {
+ type = TYPE_IDENTITY;
+ m00 = m11 = 1.0f;
+ m10 = m01 = m02 = m12 = 0.0f;
+ }
+
+ public void setToTranslation(float mx, float my) {
+ m00 = m11 = 1.0f;
+ m01 = m10 = 0.0f;
+ m02 = mx;
+ m12 = my;
+ if (mx == 0.0f && my == 0.0f) {
+ type = TYPE_IDENTITY;
+ } else {
+ type = TYPE_TRANSLATION;
+ }
+ }
+
+ public void setToScale(float scx, float scy) {
+ m00 = scx;
+ m11 = scy;
+ m10 = m01 = m02 = m12 = 0.0f;
+ if (scx != 1.0f || scy != 1.0f) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ public void setToShear(float shx, float shy) {
+ m00 = m11 = 1.0f;
+ m02 = m12 = 0.0f;
+ m01 = shx;
+ m10 = shy;
+ if (shx != 0.0f || shy != 0.0f) {
+ type = TYPE_UNKNOWN;
+ } else {
+ type = TYPE_IDENTITY;
+ }
+ }
+
+ public void setToRotation(float angle) {
+ float sin = MathFloat.sin(angle);
+ float cos = MathFloat.cos(angle);
+ if (MathFloat.abs(cos) < ZERO) {
+ cos = 0.0f;
+ sin = sin > 0.0f ? 1.0f : -1.0f;
+ } else
+ if (MathFloat.abs(sin) < ZERO) {
+ sin = 0.0f;
+ cos = cos > 0.0f ? 1.0f : -1.0f;
+ }
+ m00 = m11 = cos;
+ m01 = -sin;
+ m10 = sin;
+ m02 = m12 = 0.0f;
+ type = TYPE_UNKNOWN;
+ }
+
+ public void setToRotation(float angle, float px, float py) {
+ setToRotation(angle);
+ m02 = px * (1.0f - m00) + py * m10;
+ m12 = py * (1.0f - m00) - px * m10;
+ type = TYPE_UNKNOWN;
+ }
+
+ public static <T extends Vertex> AffineTransform getTranslateInstance(Vertex.Factory<? extends Vertex> factory, float mx, float my) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToTranslation(mx, my);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getScaleInstance(Vertex.Factory<? extends Vertex> factory, float scx, float scY) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToScale(scx, scY);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getShearInstance(Vertex.Factory<? extends Vertex> factory, float shx, float shy) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToShear(shx, shy);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getRotateInstance(Vertex.Factory<? extends Vertex> factory, float angle) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToRotation(angle);
+ return t;
+ }
+
+ public static <T extends Vertex> AffineTransform getRotateInstance(Vertex.Factory<? extends Vertex> factory, float angle, float x, float y) {
+ AffineTransform t = new AffineTransform(factory);
+ t.setToRotation(angle, x, y);
+ return t;
+ }
+
+ public void translate(float mx, float my) {
+ concatenate(AffineTransform.getTranslateInstance(pointFactory, mx, my));
+ }
+
+ public void scale(float scx, float scy) {
+ concatenate(AffineTransform.getScaleInstance(pointFactory, scx, scy));
+ }
+
+ public void shear(float shx, float shy) {
+ concatenate(AffineTransform.getShearInstance(pointFactory, shx, shy));
+ }
+
+ public void rotate(float angle) {
+ concatenate(AffineTransform.getRotateInstance(pointFactory, angle));
+ }
+
+ public void rotate(float angle, float px, float py) {
+ concatenate(AffineTransform.getRotateInstance(pointFactory, angle, px, py));
+ }
+
+ /**
+ * Multiply matrix of two AffineTransform objects.
+ * The first argument's {@link Vertex.Factory} is being used.
+ *
+ * @param t1 - the AffineTransform object is a multiplicand
+ * @param t2 - the AffineTransform object is a multiplier
+ * @return an AffineTransform object that is a result of t1 multiplied by matrix t2.
+ */
+ AffineTransform multiply(AffineTransform t1, AffineTransform t2) {
+ return new AffineTransform(t1.pointFactory,
+ t1.m00 * t2.m00 + t1.m10 * t2.m01, // m00
+ t1.m00 * t2.m10 + t1.m10 * t2.m11, // m01
+ t1.m01 * t2.m00 + t1.m11 * t2.m01, // m10
+ t1.m01 * t2.m10 + t1.m11 * t2.m11, // m11
+ t1.m02 * t2.m00 + t1.m12 * t2.m01 + t2.m02, // m02
+ t1.m02 * t2.m10 + t1.m12 * t2.m11 + t2.m12);// m12
+ }
+
+ public void concatenate(AffineTransform t) {
+ setTransform(multiply(t, this));
+ }
+
+ public void preConcatenate(AffineTransform t) {
+ setTransform(multiply(this, t));
+ }
+
+ public AffineTransform createInverse() throws NoninvertibleTransformException {
+ float det = getDeterminant();
+ if (MathFloat.abs(det) < ZERO) {
+ throw new NoninvertibleTransformException(determinantIsZero);
+ }
+ return new AffineTransform(
+ this.pointFactory,
+ m11 / det, // m00
+ -m10 / det, // m10
+ -m01 / det, // m01
+ m00 / det, // m11
+ (m01 * m12 - m11 * m02) / det, // m02
+ (m10 * m02 - m00 * m12) / det // m12
+ );
+ }
+
+ public Vertex transform(Vertex src, Vertex dst) {
+ if (dst == null) {
+ dst = pointFactory.create();
+ }
+
+ float x = src.getX();
+ float y = src.getY();
+
+ dst.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ return dst;
+ }
+
+ public void transform(Vertex[] src, int srcOff, Vertex[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ Vertex srcPoint = src[srcOff++];
+ float x = srcPoint.getX();
+ float y = srcPoint.getY();
+ Vertex dstPoint = dst[dstOff];
+ if (dstPoint == null) {
+ throw new IllegalArgumentException("dst["+dstOff+"] is null");
+ }
+ dstPoint.setCoord(x * m00 + y * m01 + m02, x * m10 + y * m11 + m12);
+ dst[dstOff++] = dstPoint;
+ }
+ }
+
+ public void transform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+ int step = 2;
+ if (src == dst && srcOff < dstOff && dstOff < srcOff + length * 2) {
+ srcOff = srcOff + length * 2 - 2;
+ dstOff = dstOff + length * 2 - 2;
+ step = -2;
+ }
+ while (--length >= 0) {
+ float x = src[srcOff + 0];
+ float y = src[srcOff + 1];
+ dst[dstOff + 0] = x * m00 + y * m01 + m02;
+ dst[dstOff + 1] = x * m10 + y * m11 + m12;
+ srcOff += step;
+ dstOff += step;
+ }
+ }
+
+ public Vertex deltaTransform(Vertex src, Vertex dst) {
+ if (dst == null) {
+ dst = pointFactory.create();
+ }
+
+ float x = src.getX();
+ float y = src.getY();
+
+ dst.setCoord(x * m00 + y * m01, x * m10 + y * m11);
+ return dst;
+ }
+
+ public void deltaTransform(float[] src, int srcOff, float[] dst, int dstOff, int length) {
+ while (--length >= 0) {
+ float x = src[srcOff++];
+ float y = src[srcOff++];
+ dst[dstOff++] = x * m00 + y * m01;
+ dst[dstOff++] = x * m10 + y * m11;
+ }
+ }
+
+ public Vertex inverseTransform(Vertex src, Vertex dst) throws NoninvertibleTransformException {
+ float det = getDeterminant();
+ if (MathFloat.abs(det) < ZERO) {
+ throw new NoninvertibleTransformException(determinantIsZero);
+ }
+ if (dst == null) {
+ dst = pointFactory.create();
+ }
+
+ float x = src.getX() - m02;
+ float y = src.getY() - m12;
+
+ dst.setCoord((x * m11 - y * m01) / det, (y * m00 - x * m10) / det);
+ return dst;
+ }
+
+ public void inverseTransform(float[] src, int srcOff, float[] dst, int dstOff, int length)
+ throws NoninvertibleTransformException
+ {
+ float det = getDeterminant();
+ if (MathFloat.abs(det) < ZERO) {
+ throw new NoninvertibleTransformException(determinantIsZero);
+ }
+
+ while (--length >= 0) {
+ float x = src[srcOff++] - m02;
+ float y = src[srcOff++] - m12;
+ dst[dstOff++] = (x * m11 - y * m01) / det;
+ dst[dstOff++] = (y * m00 - x * m10) / det;
+ }
+ }
+
+ public Path2D createTransformedShape(Path2D src) {
+ if (src == null) {
+ return null;
+ }
+ if (src instanceof Path2D) {
+ return ((Path2D)src).createTransformedShape(this);
+ }
+ PathIterator path = src.iterator(this);
+ Path2D dst = new Path2D(path.getWindingRule());
+ dst.append(path, false);
+ return dst;
+ }
+
+ @Override
+ public String toString() {
+ return
+ getClass().getName() +
+ "[[" + m00 + ", " + m01 + ", " + m02 + "], [" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ + m10 + ", " + m11 + ", " + m12 + "]]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ HashCode hash = new HashCode();
+ hash.append(m00);
+ hash.append(m01);
+ hash.append(m02);
+ hash.append(m10);
+ hash.append(m11);
+ hash.append(m12);
+ return hash.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj instanceof AffineTransform) {
+ AffineTransform t = (AffineTransform)obj;
+ return
+ m00 == t.m00 && m01 == t.m01 &&
+ m02 == t.m02 && m10 == t.m10 &&
+ m11 == t.m11 && m12 == t.m12;
+ }
+ return false;
+ }
+
+
+ /**
+ * Write AffineTrasform object to the output steam.
+ * @param stream - the output stream
+ * @throws IOException - if there are I/O errors while writing to the output strem
+ */
+ private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ }
+
+
+ /**
+ * Read AffineTransform object from the input stream
+ * @param stream - the input steam
+ * @throws IOException - if there are I/O errors while reading from the input strem
+ * @throws ClassNotFoundException - if class could not be found
+ */
+ private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ type = TYPE_UNKNOWN;
+ }
+
+}
+
diff --git a/src/jogl/classes/jogamp/graph/geom/plane/IllegalPathStateException.java b/src/jogl/classes/jogamp/graph/geom/plane/IllegalPathStateException.java
new file mode 100644
index 000000000..55211b3f9
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/geom/plane/IllegalPathStateException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+public class IllegalPathStateException extends RuntimeException {
+
+ private static final long serialVersionUID = -5158084205220481094L;
+
+ public IllegalPathStateException() {
+ }
+
+ public IllegalPathStateException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/src/jogl/classes/jogamp/graph/geom/plane/NoninvertibleTransformException.java b/src/jogl/classes/jogamp/graph/geom/plane/NoninvertibleTransformException.java
new file mode 100644
index 000000000..398a03fca
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/geom/plane/NoninvertibleTransformException.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+public class NoninvertibleTransformException extends java.lang.Exception {
+
+ private static final long serialVersionUID = 6137225240503990466L;
+
+ public NoninvertibleTransformException(String s) {
+ super(s);
+ }
+
+}
+
diff --git a/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java b/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java
new file mode 100644
index 000000000..431891361
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/geom/plane/Path2D.java
@@ -0,0 +1,428 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+import java.util.NoSuchElementException;
+
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+import jogamp.graph.math.plane.Crossing;
+
+public final class Path2D implements Cloneable {
+
+ public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD;
+ public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO;
+
+ static final String invalidWindingRuleValue = "Invalid winding rule value";
+ static final String iteratorOutOfBounds = "Iterator out of bounds";
+
+ /**
+ * The buffers size
+ */
+ private static final int BUFFER_SIZE = 10;
+
+ /**
+ * The buffers capacity
+ */
+ private static final int BUFFER_CAPACITY = 10;
+
+ /**
+ * The point's types buffer
+ */
+ byte[] types;
+
+ /**
+ * The points buffer
+ */
+ float[] points;
+
+ /**
+ * The point's type buffer size
+ */
+ int typeSize;
+
+ /**
+ * The points buffer size
+ */
+ int pointSize;
+
+ /**
+ * The path rule
+ */
+ int rule;
+
+ /**
+ * The space amount in points buffer for different segmenet's types
+ */
+ static int pointShift[] = {
+ 2, // MOVETO
+ 2, // LINETO
+ 4, // QUADTO
+ 6, // CUBICTO
+ 0}; // CLOSE
+
+ /*
+ * GeneralPath path iterator
+ */
+ class Iterator implements PathIterator {
+
+ /**
+ * The current cursor position in types buffer
+ */
+ int typeIndex;
+
+ /**
+ * The current cursor position in points buffer
+ */
+ int pointIndex;
+
+ /**
+ * The source GeneralPath object
+ */
+ Path2D p;
+
+ /**
+ * The path iterator transformation
+ */
+ AffineTransform t;
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path
+ * @param path - the source GeneralPath object
+ */
+ Iterator(Path2D path) {
+ this(path, null);
+ }
+
+ /**
+ * Constructs a new GeneralPath.Iterator for given general path and transformation
+ * @param path - the source GeneralPath object
+ * @param at - the AffineTransform object to apply rectangle path
+ */
+ Iterator(Path2D path, AffineTransform at) {
+ this.p = path;
+ this.t = at;
+ }
+
+ public int getWindingRule() {
+ return p.getWindingRule();
+ }
+
+ public boolean isDone() {
+ return typeIndex >= p.typeSize;
+ }
+
+ public void next() {
+ typeIndex++;
+ }
+
+ public int currentSegment(float[] coords) {
+ if (isDone()) {
+ throw new NoSuchElementException(iteratorOutOfBounds);
+ }
+ int type = p.types[typeIndex];
+ int count = Path2D.pointShift[type];
+ System.arraycopy(p.points, pointIndex, coords, 0, count);
+ if (t != null) {
+ t.transform(coords, 0, coords, 0, count / 2);
+ }
+ pointIndex += count;
+ return type;
+ }
+
+ }
+
+ public Path2D() {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ }
+
+ public Path2D(int rule) {
+ this(rule, BUFFER_SIZE);
+ }
+
+ public Path2D(int rule, int initialCapacity) {
+ setWindingRule(rule);
+ types = new byte[initialCapacity];
+ points = new float[initialCapacity * 2];
+ }
+
+ public Path2D(Path2D path) {
+ this(WIND_NON_ZERO, BUFFER_SIZE);
+ PathIterator p = path.iterator(null);
+ setWindingRule(p.getWindingRule());
+ append(p, false);
+ }
+
+ public void setWindingRule(int rule) {
+ if (rule != WIND_EVEN_ODD && rule != WIND_NON_ZERO) {
+ throw new NoSuchElementException(invalidWindingRuleValue);
+ }
+ this.rule = rule;
+ }
+
+ public int getWindingRule() {
+ return rule;
+ }
+
+ /**
+ * Checks points and types buffer size to add pointCount points. If necessary realloc buffers to enlarge size.
+ * @param pointCount - the point count to be added in buffer
+ */
+ void checkBuf(int pointCount, boolean checkMove) {
+ if (checkMove && typeSize == 0) {
+ throw new IllegalPathStateException("First segment should be SEG_MOVETO type");
+ }
+ if (typeSize == types.length) {
+ byte tmp[] = new byte[typeSize + BUFFER_CAPACITY];
+ System.arraycopy(types, 0, tmp, 0, typeSize);
+ types = tmp;
+ }
+ if (pointSize + pointCount > points.length) {
+ float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)];
+ System.arraycopy(points, 0, tmp, 0, pointSize);
+ points = tmp;
+ }
+ }
+
+ public void moveTo(float x, float y) {
+ if (typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_MOVETO) {
+ points[pointSize - 2] = x;
+ points[pointSize - 1] = y;
+ } else {
+ checkBuf(2, false);
+ types[typeSize++] = PathIterator.SEG_MOVETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+ }
+
+ public void lineTo(float x, float y) {
+ checkBuf(2, true);
+ types[typeSize++] = PathIterator.SEG_LINETO;
+ points[pointSize++] = x;
+ points[pointSize++] = y;
+ }
+
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ checkBuf(4, true);
+ types[typeSize++] = PathIterator.SEG_QUADTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ }
+
+ public void curveTo(float x1, float y1, float x2, float y2, float x3, float y3) {
+ checkBuf(6, true);
+ types[typeSize++] = PathIterator.SEG_CUBICTO;
+ points[pointSize++] = x1;
+ points[pointSize++] = y1;
+ points[pointSize++] = x2;
+ points[pointSize++] = y2;
+ points[pointSize++] = x3;
+ points[pointSize++] = y3;
+ }
+
+ final public int size() {
+ return typeSize;
+ }
+
+ final public boolean isClosed() {
+ return typeSize > 0 && types[typeSize - 1] == PathIterator.SEG_CLOSE ;
+ }
+
+ public void closePath() {
+ if (!isClosed()) {
+ checkBuf(0, true);
+ types[typeSize++] = PathIterator.SEG_CLOSE;
+ }
+ }
+
+ public String toString() {
+ return "[size "+size()+", closed "+isClosed()+"]";
+ }
+
+ public void append(Path2D path, boolean connect) {
+ PathIterator p = path.iterator(null);
+ append(p, connect);
+ }
+
+ public void append(PathIterator path, boolean connect) {
+ while (!path.isDone()) {
+ float coords[] = new float[6];
+ switch (path.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (!connect || typeSize == 0) {
+ moveTo(coords[0], coords[1]);
+ break;
+ }
+ if (types[typeSize - 1] != PathIterator.SEG_CLOSE &&
+ points[pointSize - 2] == coords[0] &&
+ points[pointSize - 1] == coords[1])
+ {
+ break;
+ }
+ // NO BREAK;
+ case PathIterator.SEG_LINETO:
+ lineTo(coords[0], coords[1]);
+ break;
+ case PathIterator.SEG_QUADTO:
+ quadTo(coords[0], coords[1], coords[2], coords[3]);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]);
+ break;
+ case PathIterator.SEG_CLOSE:
+ closePath();
+ break;
+ }
+ path.next();
+ connect = false;
+ }
+ }
+
+ public SVertex getCurrentPoint() {
+ if (typeSize == 0) {
+ return null;
+ }
+ int j = pointSize - 2;
+ if (types[typeSize - 1] == PathIterator.SEG_CLOSE) {
+
+ for (int i = typeSize - 2; i > 0; i--) {
+ int type = types[i];
+ if (type == PathIterator.SEG_MOVETO) {
+ break;
+ }
+ j -= pointShift[type];
+ }
+ }
+ return new SVertex(points[j], points[j + 1]);
+ }
+
+ public void reset() {
+ typeSize = 0;
+ pointSize = 0;
+ }
+
+ public void transform(AffineTransform t) {
+ t.transform(points, 0, points, 0, pointSize / 2);
+ }
+
+ public Path2D createTransformedShape(AffineTransform t) {
+ Path2D p = (Path2D)clone();
+ if (t != null) {
+ p.transform(t);
+ }
+ return p;
+ }
+
+ public final synchronized AABBox getBounds2D() {
+ float rx1, ry1, rx2, ry2;
+ if (pointSize == 0) {
+ rx1 = ry1 = rx2 = ry2 = 0.0f;
+ } else {
+ int i = pointSize - 1;
+ ry1 = ry2 = points[i--];
+ rx1 = rx2 = points[i--];
+ while (i > 0) {
+ float y = points[i--];
+ float x = points[i--];
+ if (x < rx1) {
+ rx1 = x;
+ } else
+ if (x > rx2) {
+ rx2 = x;
+ }
+ if (y < ry1) {
+ ry1 = y;
+ } else
+ if (y > ry2) {
+ ry2 = y;
+ }
+ }
+ }
+ return new AABBox(rx1, ry1, 0f, rx2, ry2, 0f);
+ }
+
+ /**
+ * Checks cross count according to path rule to define is it point inside shape or not.
+ * @param cross - the point cross count
+ * @return true if point is inside path, or false otherwise
+ */
+ boolean isInside(int cross) {
+ if (rule == WIND_NON_ZERO) {
+ return Crossing.isInsideNonZero(cross);
+ }
+ return Crossing.isInsideEvenOdd(cross);
+ }
+
+ public boolean contains(float px, float py) {
+ return isInside(Crossing.crossShape(this, px, py));
+ }
+
+ public boolean contains(float rx, float ry, float rw, float rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross != Crossing.CROSSING && isInside(cross);
+ }
+
+ public boolean intersects(float rx, float ry, float rw, float rh) {
+ int cross = Crossing.intersectShape(this, rx, ry, rw, rh);
+ return cross == Crossing.CROSSING || isInside(cross);
+ }
+
+ public boolean contains(Vertex p) {
+ return contains(p.getX(), p.getY());
+ }
+
+ public boolean contains(AABBox r) {
+ return contains(r);
+ }
+
+ public boolean intersects(AABBox r) {
+ return intersects(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight());
+ }
+
+ public PathIterator iterator() {
+ return new Iterator(this);
+ }
+
+ public PathIterator iterator(AffineTransform t) {
+ return new Iterator(this, t);
+ }
+
+ /* public PathIterator getPathIterator(AffineTransform t, float flatness) {
+ return new FlatteningPathIterator(getPathIterator(t), flatness);
+ } */
+
+ @Override
+ public Object clone() {
+ try {
+ Path2D p = (Path2D) super.clone();
+ p.types = types.clone();
+ p.points = points.clone();
+ return p;
+ } catch (CloneNotSupportedException e) {
+ throw new InternalError();
+ }
+ }
+}
+
diff --git a/src/jogl/classes/jogamp/graph/geom/plane/PathIterator.java b/src/jogl/classes/jogamp/graph/geom/plane/PathIterator.java
new file mode 100644
index 000000000..8868a8c58
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/geom/plane/PathIterator.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.geom.plane;
+
+public interface PathIterator {
+
+ public static final int WIND_EVEN_ODD = 0;
+ public static final int WIND_NON_ZERO = 1;
+
+ public static final int SEG_MOVETO = 0;
+ public static final int SEG_LINETO = 1;
+ public static final int SEG_QUADTO = 2;
+ public static final int SEG_CUBICTO = 3;
+ public static final int SEG_CLOSE = 4;
+
+ public int getWindingRule();
+
+ public boolean isDone();
+
+ public void next();
+
+ public int currentSegment(float[] coords);
+
+}
+
diff --git a/src/jogl/classes/jogamp/graph/math/MathFloat.java b/src/jogl/classes/jogamp/graph/math/MathFloat.java
new file mode 100644
index 000000000..0b8d69eba
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/math/MathFloat.java
@@ -0,0 +1,45 @@
+/**
+ * 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.math;
+
+public class MathFloat {
+
+ public static final float E = 2.7182818284590452354f;
+
+ public static final float PI = 3.14159265358979323846f;
+
+ public static float abs(float a) { return (float) java.lang.Math.abs(a); }
+ public static float pow(float a, float b) { return (float) java.lang.Math.pow(a, b); }
+
+ public static float sin(float a) { return (float) java.lang.Math.sin(a); }
+ public static float cos(float a) { return (float) java.lang.Math.cos(a); }
+ public static float acos(float a) { return (float) java.lang.Math.acos(a); }
+
+ public static float sqrt(float a) { return (float) java.lang.Math.sqrt(a); }
+
+}
diff --git a/src/jogl/classes/jogamp/graph/math/plane/Crossing.java b/src/jogl/classes/jogamp/graph/math/plane/Crossing.java
new file mode 100644
index 000000000..8f8638632
--- /dev/null
+++ b/src/jogl/classes/jogamp/graph/math/plane/Crossing.java
@@ -0,0 +1,897 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Denis M. Kishenko
+ */
+package jogamp.graph.math.plane;
+
+import jogamp.graph.geom.plane.Path2D;
+import jogamp.graph.geom.plane.PathIterator;
+import jogamp.graph.math.MathFloat;
+
+
+public class Crossing {
+
+ /**
+ * Allowable tolerance for bounds comparison
+ */
+ static final float DELTA = (float) 1E-5;
+
+ /**
+ * If roots have distance less then <code>ROOT_DELTA</code> they are double
+ */
+ static final float ROOT_DELTA = (float) 1E-10;
+
+ /**
+ * Rectangle cross segment
+ */
+ public static final int CROSSING = 255;
+
+ /**
+ * Unknown crossing result
+ */
+ static final int UNKNOWN = 254;
+
+ /**
+ * Solves quadratic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveQuad(float eqn[], float res[]) {
+ float a = eqn[2];
+ float b = eqn[1];
+ float c = eqn[0];
+ int rc = 0;
+ if (a == 0.0) {
+ if (b == 0.0) {
+ return -1;
+ }
+ res[rc++] = -c / b;
+ } else {
+ float d = b * b - 4.0f * a * c;
+ // d < 0.0
+ if (d < 0.0) {
+ return 0;
+ }
+ d = MathFloat.sqrt(d);
+ res[rc++] = (- b + d) / (a * 2.0f);
+ // d != 0.0
+ if (d != 0.0) {
+ res[rc++] = (- b - d) / (a * 2.0f);
+ }
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Solves cubic equation
+ * @param eqn - the coefficients of the equation
+ * @param res - the roots of the equation
+ * @return a number of roots
+ */
+ public static int solveCubic(float eqn[], float res[]) {
+ float d = eqn[3];
+ if (d == 0) {
+ return solveQuad(eqn, res);
+ }
+ float a = eqn[2] / d;
+ float b = eqn[1] / d;
+ float c = eqn[0] / d;
+ int rc = 0;
+
+ float Q = (a * a - 3.0f * b) / 9.0f;
+ float R = (2.0f * a * a * a - 9.0f * a * b + 27.0f * c) / 54.0f;
+ float Q3 = Q * Q * Q;
+ float R2 = R * R;
+ float n = - a / 3.0f;
+
+ if (R2 < Q3) {
+ float t = MathFloat.acos(R / MathFloat.sqrt(Q3)) / 3.0f;
+ float p = 2.0f * MathFloat.PI / 3.0f;
+ float m = -2.0f * MathFloat.sqrt(Q);
+ res[rc++] = m * MathFloat.cos(t) + n;
+ res[rc++] = m * MathFloat.cos(t + p) + n;
+ res[rc++] = m * MathFloat.cos(t - p) + n;
+ } else {
+// Debug.println("R2 >= Q3 (" + R2 + "/" + Q3 + ")");
+ float A = MathFloat.pow(MathFloat.abs(R) + MathFloat.sqrt(R2 - Q3), 1.0f / 3.0f);
+ if (R > 0.0) {
+ A = -A;
+ }
+// if (A == 0.0) {
+ if (-ROOT_DELTA < A && A < ROOT_DELTA) {
+ res[rc++] = n;
+ } else {
+ float B = Q / A;
+ res[rc++] = A + B + n;
+// if (R2 == Q3) {
+ float delta = R2 - Q3;
+ if (-ROOT_DELTA < delta && delta < ROOT_DELTA) {
+ res[rc++] = - (A + B) / 2.0f + n;
+ }
+ }
+
+ }
+ return fixRoots(res, rc);
+ }
+
+ /**
+ * Excludes float roots. Roots are float if they lies enough close with each other.
+ * @param res - the roots
+ * @param rc - the roots count
+ * @return new roots count
+ */
+ static int fixRoots(float res[], int rc) {
+ int tc = 0;
+ for(int i = 0; i < rc; i++) {
+ out: {
+ for(int j = i + 1; j < rc; j++) {
+ if (isZero(res[i] - res[j])) {
+ break out;
+ }
+ }
+ res[tc++] = res[i];
+ }
+ }
+ return tc;
+ }
+
+ /**
+ * QuadCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class QuadCurve {
+
+ float ax, ay, bx, by;
+ float Ax, Ay, Bx, By;
+
+ public QuadCurve(float x1, float y1, float cx, float cy, float x2, float y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx - x1;
+ by = cy - y1;
+
+ Bx = bx + bx; // Bx = 2.0 * bx
+ Ax = ax - Bx; // Ax = ax - 2.0 * bx
+
+ By = by + by; // By = 2.0 * by
+ Ay = ay - By; // Ay = ay - 2.0 * by
+ }
+
+ int cross(float res[], int rc, float py1, float py2) {
+ int cross = 0;
+
+ for (int i = 0; i < rc; i++) {
+ float t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : ax - bx) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != bx ? ax - bx : bx) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ float ry = t * (t * Ay + By);
+ // ry = t * t * Ay + t * By
+ if (ry > py2) {
+ float rxt = t * Ax + bx;
+ // rxt = 2.0 * t * Ax + Bx = 2.0 * t * Ax + 2.0 * bx
+ if (rxt > -DELTA && rxt < DELTA) {
+ continue;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } // for
+
+ return cross;
+ }
+
+ int solvePoint(float res[], float px) {
+ float eqn[] = {-px, Bx, Ax};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtrem(float res[]) {
+ int rc = 0;
+ if (Ax != 0.0) {
+ res[rc++] = - Bx / (Ax + Ax);
+ }
+ if (Ay != 0.0) {
+ res[rc++] = - By / (Ay + Ay);
+ }
+ return rc;
+ }
+
+ int addBound(float bound[], int bc, float res[], int rc, float minX, float maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ float t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ float rx = t * (t * Ax + Bx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * Ay + By);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * CubicCurve class provides basic functionality to find curve crossing and calculating bounds
+ */
+ public static class CubicCurve {
+
+ float ax, ay, bx, by, cx, cy;
+ float Ax, Ay, Bx, By, Cx, Cy;
+ float Ax3, Bx2;
+
+ public CubicCurve(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2) {
+ ax = x2 - x1;
+ ay = y2 - y1;
+ bx = cx1 - x1;
+ by = cy1 - y1;
+ cx = cx2 - x1;
+ cy = cy2 - y1;
+
+ Cx = bx + bx + bx; // Cx = 3.0 * bx
+ Bx = cx + cx + cx - Cx - Cx; // Bx = 3.0 * cx - 6.0 * bx
+ Ax = ax - Bx - Cx; // Ax = ax - 3.0 * cx + 3.0 * bx
+
+ Cy = by + by + by; // Cy = 3.0 * by
+ By = cy + cy + cy - Cy - Cy; // By = 3.0 * cy - 6.0 * by
+ Ay = ay - By - Cy; // Ay = ay - 3.0 * cy + 3.0 * by
+
+ Ax3 = Ax + Ax + Ax;
+ Bx2 = Bx + Bx;
+ }
+
+ int cross(float res[], int rc, float py1, float py2) {
+ int cross = 0;
+ for (int i = 0; i < rc; i++) {
+ float t = res[i];
+
+ // CURVE-OUTSIDE
+ if (t < -DELTA || t > 1 + DELTA) {
+ continue;
+ }
+ // CURVE-START
+ if (t < DELTA) {
+ if (py1 < 0.0 && (bx != 0.0 ? bx : (cx != bx ? cx - bx : ax - cx)) < 0.0) {
+ cross--;
+ }
+ continue;
+ }
+ // CURVE-END
+ if (t > 1 - DELTA) {
+ if (py1 < ay && (ax != cx ? ax - cx : (cx != bx ? cx - bx : bx)) > 0.0) {
+ cross++;
+ }
+ continue;
+ }
+ // CURVE-INSIDE
+ float ry = t * (t * (t * Ay + By) + Cy);
+ // ry = t * t * t * Ay + t * t * By + t * Cy
+ if (ry > py2) {
+ float rxt = t * (t * Ax3 + Bx2) + Cx;
+ // rxt = 3.0 * t * t * Ax + 2.0 * t * Bx + Cx
+ if (rxt > -DELTA && rxt < DELTA) {
+ rxt = t * (Ax3 + Ax3) + Bx2;
+ // rxt = 6.0 * t * Ax + 2.0 * Bx
+ if (rxt < -DELTA || rxt > DELTA) {
+ // Inflection point
+ continue;
+ }
+ rxt = ax;
+ }
+ cross += rxt > 0.0 ? 1 : -1;
+ }
+ } //for
+
+ return cross;
+ }
+
+ int solvePoint(float res[], float px) {
+ float eqn[] = {-px, Cx, Bx, Ax};
+ return solveCubic(eqn, res);
+ }
+
+ int solveExtremX(float res[]) {
+ float eqn[] = {Cx, Bx2, Ax3};
+ return solveQuad(eqn, res);
+ }
+
+ int solveExtremY(float res[]) {
+ float eqn[] = {Cy, By + By, Ay + Ay + Ay};
+ return solveQuad(eqn, res);
+ }
+
+ int addBound(float bound[], int bc, float res[], int rc, float minX, float maxX, boolean changeId, int id) {
+ for(int i = 0; i < rc; i++) {
+ float t = res[i];
+ if (t > -DELTA && t < 1 + DELTA) {
+ float rx = t * (t * (t * Ax + Bx) + Cx);
+ if (minX <= rx && rx <= maxX) {
+ bound[bc++] = t;
+ bound[bc++] = rx;
+ bound[bc++] = t * (t * (t * Ay + By) + Cy);
+ bound[bc++] = id;
+ if (changeId) {
+ id++;
+ }
+ }
+ }
+ }
+ return bc;
+ }
+
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross line.
+ */
+ public static int crossLine(float x1, float y1, float x2, float y2, float x, float y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < x2) ||
+ (x > x1 && x > x2) ||
+ (y > y1 && y > y2) ||
+ (x1 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < y2) {
+ } else {
+ // INSIDE
+ if ((y2 - y1) * (x - x1) / (x2 - x1) <= y - y1) {
+ // INSIDE-UP
+ return 0;
+ }
+ }
+
+ // START
+ if (x == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // END
+ if (x == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ // INSIDE-DOWN
+ return x1 < x2 ? 1 : -1;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross quard curve
+ */
+ public static int crossQuad(float x1, float y1, float cx, float cy, float x2, float y2, float x, float y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx && x < x2) ||
+ (x > x1 && x > cx && x > x2) ||
+ (y > y1 && y > cy && y > y2) ||
+ (x1 == cx && cx == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ float px = x - x1;
+ float py = y - y1;
+ float res[] = new float[3];
+ int rc = c.solvePoint(res, px);
+
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross cubic curve
+ */
+ public static int crossCubic(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, float x, float y) {
+
+ // LEFT/RIGHT/UP/EMPTY
+ if ((x < x1 && x < cx1 && x < cx2 && x < x2) ||
+ (x > x1 && x > cx1 && x > cx2 && x > x2) ||
+ (y > y1 && y > cy1 && y > cy2 && y > y2) ||
+ (x1 == cx1 && cx1 == cx2 && cx2 == x2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (y < y1 && y < cy1 && y < cy2 && y < y2 && x != x1 && x != x2) {
+ if (x1 < x2) {
+ return x1 < x && x < x2 ? 1 : 0;
+ }
+ return x2 < x && x < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ float px = x - x1;
+ float py = y - y1;
+ float res[] = new float[3];
+ int rc = c.solvePoint(res, px);
+ return c.cross(res, rc, py, py);
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross path
+ */
+ public static int crossPath(PathIterator p, float x, float y) {
+ int cross = 0;
+ float mx, my, cx, cy;
+ mx = my = cx = cy = 0.0f;
+ float coords[] = new float[6];
+
+ while (!p.isDone()) {
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ cross += crossLine(cx, cy, cx = coords[0], cy = coords[1], x, y);
+ break;
+ case PathIterator.SEG_QUADTO:
+ cross += crossQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], x, y);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ cross += crossCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], x, y);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ cross += crossLine(cx, cy, cx = mx, cy = my, x, y);
+ }
+ break;
+ }
+
+ // checks if the point (x,y) is the vertex of shape with PathIterator p
+ if (x == cx && y == cy) {
+ cross = 0;
+ cy = my;
+ break;
+ }
+ p.next();
+ }
+ if (cy != my) {
+ cross += crossLine(cx, cy, mx, my, x, y);
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times ray from point (x,y) cross shape
+ */
+ public static int crossShape(Path2D s, float x, float y) {
+ if (!s.getBounds2D().contains(x, y)) {
+ return 0;
+ }
+ return crossPath(s.iterator(null), x, y);
+ }
+
+ /**
+ * Returns true if value enough small
+ */
+ public static boolean isZero(float val) {
+ return -DELTA < val && val < DELTA;
+ }
+
+ /**
+ * Sort bound array
+ */
+ static void sortBound(float bound[], int bc) {
+ for(int i = 0; i < bc - 4; i += 4) {
+ int k = i;
+ for(int j = i + 4; j < bc; j += 4) {
+ if (bound[k] > bound[j]) {
+ k = j;
+ }
+ }
+ if (k != i) {
+ float tmp = bound[i];
+ bound[i] = bound[k];
+ bound[k] = tmp;
+ tmp = bound[i + 1];
+ bound[i + 1] = bound[k + 1];
+ bound[k + 1] = tmp;
+ tmp = bound[i + 2];
+ bound[i + 2] = bound[k + 2];
+ bound[k + 2] = tmp;
+ tmp = bound[i + 3];
+ bound[i + 3] = bound[k + 3];
+ bound[k + 3] = tmp;
+ }
+ }
+ }
+
+ /**
+ * Returns are bounds intersect or not intersect rectangle
+ */
+ static int crossBound(float bound[], int bc, float py1, float py2) {
+
+ // LEFT/RIGHT
+ if (bc == 0) {
+ return 0;
+ }
+
+ // Check Y coordinate
+ int up = 0;
+ int down = 0;
+ for(int i = 2; i < bc; i += 4) {
+ if (bound[i] < py1) {
+ up++;
+ continue;
+ }
+ if (bound[i] > py2) {
+ down++;
+ continue;
+ }
+ return CROSSING;
+ }
+
+ // UP
+ if (down == 0) {
+ return 0;
+ }
+
+ if (up != 0) {
+ // bc >= 2
+ sortBound(bound, bc);
+ boolean sign = bound[2] > py2;
+ for(int i = 6; i < bc; i += 4) {
+ boolean sign2 = bound[i] > py2;
+ if (sign != sign2 && bound[i + 1] != bound[i - 3]) {
+ return CROSSING;
+ }
+ sign = sign2;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross line or the are intersect
+ */
+ public static int intersectLine(float x1, float y1, float x2, float y2, float rx1, float ry1, float rx2, float ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < y2) {
+ } else {
+
+ // INSIDE
+ if (x1 == x2) {
+ return CROSSING;
+ }
+
+ // Build bound
+ float bx1, bx2;
+ if (x1 < x2) {
+ bx1 = x1 < rx1 ? rx1 : x1;
+ bx2 = x2 < rx2 ? x2 : rx2;
+ } else {
+ bx1 = x2 < rx1 ? rx1 : x2;
+ bx2 = x1 < rx2 ? x1 : rx2;
+ }
+ float k = (y2 - y1) / (x2 - x1);
+ float by1 = k * (bx1 - x1) + y1;
+ float by2 = k * (bx2 - x1) + y1;
+
+ // BOUND-UP
+ if (by1 < ry1 && by2 < ry1) {
+ return 0;
+ }
+
+ // BOUND-DOWN
+ if (by1 > ry2 && by2 > ry2) {
+ } else {
+ return CROSSING;
+ }
+ }
+
+ // EMPTY
+ if (x1 == x2) {
+ return 0;
+ }
+
+ // CURVE-START
+ if (rx1 == x1) {
+ return x1 < x2 ? 0 : -1;
+ }
+
+ // CURVE-END
+ if (rx1 == x2) {
+ return x1 < x2 ? 1 : 0;
+ }
+
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross quad curve or the are intersect
+ */
+ public static int intersectQuad(float x1, float y1, float cx, float cy, float x2, float y2, float rx1, float ry1, float rx2, float ry2) {
+
+ // LEFT/RIGHT/UP ------------------------------------------------------
+ if ((rx2 < x1 && rx2 < cx && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN ---------------------------------------------------------------
+ if (ry2 < y1 && ry2 < cy && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE -------------------------------------------------------------
+ QuadCurve c = new QuadCurve(x1, y1, cx, cy, x2, y2);
+ float px1 = rx1 - x1;
+ float py1 = ry1 - y1;
+ float px2 = rx2 - x1;
+ float py2 = ry2 - y1;
+
+ float res1[] = new float[3];
+ float res2[] = new float[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // INSIDE-LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ // Build bound --------------------------------------------------------
+ float minX = px1 - DELTA;
+ float maxX = px2 + DELTA;
+ float bound[] = new float[28];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extremal points`
+ rc2 = c.solveExtrem(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 4;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0f;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 5;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross cubic curve or the are intersect
+ */
+ public static int intersectCubic(float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2, float rx1, float ry1, float rx2, float ry2) {
+
+ // LEFT/RIGHT/UP
+ if ((rx2 < x1 && rx2 < cx1 && rx2 < cx2 && rx2 < x2) ||
+ (rx1 > x1 && rx1 > cx1 && rx1 > cx2 && rx1 > x2) ||
+ (ry1 > y1 && ry1 > cy1 && ry1 > cy2 && ry1 > y2))
+ {
+ return 0;
+ }
+
+ // DOWN
+ if (ry2 < y1 && ry2 < cy1 && ry2 < cy2 && ry2 < y2 && rx1 != x1 && rx1 != x2) {
+ if (x1 < x2) {
+ return x1 < rx1 && rx1 < x2 ? 1 : 0;
+ }
+ return x2 < rx1 && rx1 < x1 ? -1 : 0;
+ }
+
+ // INSIDE
+ CubicCurve c = new CubicCurve(x1, y1, cx1, cy1, cx2, cy2, x2, y2);
+ float px1 = rx1 - x1;
+ float py1 = ry1 - y1;
+ float px2 = rx2 - x1;
+ float py2 = ry2 - y1;
+
+ float res1[] = new float[3];
+ float res2[] = new float[3];
+ int rc1 = c.solvePoint(res1, px1);
+ int rc2 = c.solvePoint(res2, px2);
+
+ // LEFT/RIGHT
+ if (rc1 == 0 && rc2 == 0) {
+ return 0;
+ }
+
+ float minX = px1 - DELTA;
+ float maxX = px2 + DELTA;
+
+ // Build bound --------------------------------------------------------
+ float bound[] = new float[40];
+ int bc = 0;
+ // Add roots
+ bc = c.addBound(bound, bc, res1, rc1, minX, maxX, false, 0);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, false, 1);
+ // Add extrimal points
+ rc2 = c.solveExtremX(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 2);
+ rc2 = c.solveExtremY(res2);
+ bc = c.addBound(bound, bc, res2, rc2, minX, maxX, true, 4);
+ // Add start and end
+ if (rx1 < x1 && x1 < rx2) {
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 0.0f;
+ bound[bc++] = 6;
+ }
+ if (rx1 < x2 && x2 < rx2) {
+ bound[bc++] = 1.0f;
+ bound[bc++] = c.ax;
+ bound[bc++] = c.ay;
+ bound[bc++] = 7;
+ }
+ // End build bound ----------------------------------------------------
+
+ int cross = crossBound(bound, bc, py1, py2);
+ if (cross != UNKNOWN) {
+ return cross;
+ }
+ return c.cross(res1, rc1, py1, py2);
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross path or the are intersect
+ */
+ public static int intersectPath(PathIterator p, float x, float y, float w, float h) {
+
+ int cross = 0;
+ int count;
+ float mx, my, cx, cy;
+ mx = my = cx = cy = 0.0f;
+ float coords[] = new float[6];
+
+ float rx1 = x;
+ float ry1 = y;
+ float rx2 = x + w;
+ float ry2 = y + h;
+
+ while (!p.isDone()) {
+ count = 0;
+ switch (p.currentSegment(coords)) {
+ case PathIterator.SEG_MOVETO:
+ if (cx != mx || cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ mx = cx = coords[0];
+ my = cy = coords[1];
+ break;
+ case PathIterator.SEG_LINETO:
+ count = intersectLine(cx, cy, cx = coords[0], cy = coords[1], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_QUADTO:
+ count = intersectQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CUBICTO:
+ count = intersectCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], cy = coords[5], rx1, ry1, rx2, ry2);
+ break;
+ case PathIterator.SEG_CLOSE:
+ if (cy != my || cx != mx) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ }
+ cx = mx;
+ cy = my;
+ break;
+ }
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ p.next();
+ }
+ if (cy != my) {
+ count = intersectLine(cx, cy, mx, my, rx1, ry1, rx2, ry2);
+ if (count == CROSSING) {
+ return CROSSING;
+ }
+ cross += count;
+ }
+ return cross;
+ }
+
+ /**
+ * Returns how many times rectangle stripe cross shape or the are intersect
+ */
+ public static int intersectShape(Path2D s, float x, float y, float w, float h) {
+ if (!s.getBounds2D().intersects(x, y, w, h)) {
+ return 0;
+ }
+ return intersectPath(s.iterator(null), x, y, w, h);
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for non zero path rule
+ */
+ public static boolean isInsideNonZero(int cross) {
+ return cross != 0;
+ }
+
+ /**
+ * Returns true if cross count correspond inside location for even-odd path rule
+ */
+ public static boolean isInsideEvenOdd(int cross) {
+ return (cross & 1) != 0;
+ }
+}
diff --git a/src/jogl/classes/org/apache/harmony/misc/HashCode.java b/src/jogl/classes/org/apache/harmony/misc/HashCode.java
new file mode 100644
index 000000000..e8ce8f620
--- /dev/null
+++ b/src/jogl/classes/org/apache/harmony/misc/HashCode.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.misc;
+
+/**
+ * This class is a convenience method to sequentially calculate hash code of the
+ * object based on the field values. The result depends on the order of elements
+ * appended. The exact formula is the same as for
+ * <code>java.util.List.hashCode</code>.
+ *
+ * If you need order independent hash code just summate, multiply or XOR all
+ * elements.
+ *
+ * <p>
+ * Suppose we have class:
+ *
+ * <pre><code>
+ * class Thing {
+ * long id;
+ * String name;
+ * float weight;
+ * }
+ * </code></pre>
+ *
+ * The hash code calculation can be expressed in 2 forms.
+ *
+ * <p>
+ * For maximum performance:
+ *
+ * <pre><code>
+ * public int hashCode() {
+ * int hashCode = HashCode.EMPTY_HASH_CODE;
+ * hashCode = HashCode.combine(hashCode, id);
+ * hashCode = HashCode.combine(hashCode, name);
+ * hashCode = HashCode.combine(hashCode, weight);
+ * return hashCode;
+ * }
+ * </code></pre>
+ *
+ * <p>
+ * For convenience: <code><pre>
+ * public int hashCode() {
+ * return new HashCode().append(id).append(name).append(weight).hashCode();
+ * }
+ * </code></pre>
+ *
+ * @see java.util.List#hashCode()
+ */
+public final class HashCode {
+ /**
+ * The hashCode value before any data is appended, equals to 1.
+ * @see java.util.List#hashCode()
+ */
+ public static final int EMPTY_HASH_CODE = 1;
+
+ private int hashCode = EMPTY_HASH_CODE;
+
+ /**
+ * Returns accumulated hashCode
+ */
+ public final int hashCode() {
+ return hashCode;
+ }
+
+ /**
+ * Combines hashCode of previous elements sequence and value's hashCode.
+ * @param hashCode previous hashCode value
+ * @param value new element
+ * @return combined hashCode
+ */
+ public static int combine(int hashCode, boolean value) {
+ int v = value ? 1231 : 1237;
+ return combine(hashCode, v);
+ }
+
+ /**
+ * Combines hashCode of previous elements sequence and value's hashCode.
+ * @param hashCode previous hashCode value
+ * @param value new element
+ * @return combined hashCode
+ */
+ public static int combine(int hashCode, long value) {
+ int v = (int) (value ^ (value >>> 32));
+ return combine(hashCode, v);
+ }
+
+ /**
+ * Combines hashCode of previous elements sequence and value's hashCode.
+ * @param hashCode previous hashCode value
+ * @param value new element
+ * @return combined hashCode
+ */
+ public static int combine(int hashCode, float value) {
+ int v = Float.floatToIntBits(value);
+ return combine(hashCode, v);
+ }
+
+ /**
+ * Combines hashCode of previous elements sequence and value's hashCode.
+ * @param hashCode previous hashCode value
+ * @param value new element
+ * @return combined hashCode
+ */
+ public static int combine(int hashCode, double value) {
+ long v = Double.doubleToLongBits(value);
+ return combine(hashCode, v);
+ }
+
+ /**
+ * Combines hashCode of previous elements sequence and value's hashCode.
+ * @param hashCode previous hashCode value
+ * @param value new element
+ * @return combined hashCode
+ */
+ public static int combine(int hashCode, Object value) {
+ return combine(hashCode, value.hashCode());
+ }
+
+ /**
+ * Combines hashCode of previous elements sequence and value's hashCode.
+ * @param hashCode previous hashCode value
+ * @param value new element
+ * @return combined hashCode
+ */
+ public static int combine(int hashCode, int value) {
+ return 31 * hashCode + value;
+ }
+
+ /**
+ * Appends value's hashCode to the current hashCode.
+ * @param value new element
+ * @return this
+ */
+ public final HashCode append(int value) {
+ hashCode = combine(hashCode, value);
+ return this;
+ }
+
+ /**
+ * Appends value's hashCode to the current hashCode.
+ * @param value new element
+ * @return this
+ */
+ public final HashCode append(long value) {
+ hashCode = combine(hashCode, value);
+ return this;
+ }
+
+ /**
+ * Appends value's hashCode to the current hashCode.
+ * @param value new element
+ * @return this
+ */
+ public final HashCode append(float value) {
+ hashCode = combine(hashCode, value);
+ return this;
+ }
+
+ /**
+ * Appends value's hashCode to the current hashCode.
+ * @param value new element
+ * @return this
+ */
+ public final HashCode append(double value) {
+ hashCode = combine(hashCode, value);
+ return this;
+ }
+
+ /**
+ * Appends value's hashCode to the current hashCode.
+ * @param value new element
+ * @return this
+ */
+ public final HashCode append(boolean value) {
+ hashCode = combine(hashCode, value);
+ return this;
+ }
+
+ /**
+ * Appends value's hashCode to the current hashCode.
+ * @param value new element
+ * @return this
+ */
+ public final HashCode append(Object value) {
+ hashCode = combine(hashCode, value);
+ return this;
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java b/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java
new file mode 100644
index 000000000..9ad4eb41a
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/TestRegionRenderer01.java
@@ -0,0 +1,156 @@
+package com.jogamp.opengl.test.junit.graph;
+
+import java.io.IOException;
+
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.graph.demos.GPURegionGLListener01;
+import com.jogamp.opengl.test.junit.graph.demos.GPURegionGLListener02;
+import com.jogamp.opengl.test.junit.graph.demos.GPURegionRendererListenerBase01;
+
+
+public class TestRegionRenderer01 {
+
+ public static void main(String args[]) throws IOException {
+ String tstname = TestRegionRenderer01.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+ @BeforeClass
+ public static void initClass() {
+ GLProfile.initSingleton(true);
+ NativeWindowFactory.initSingleton(true);
+ }
+
+ static void destroyWindow(GLWindow window) {
+ if(null!=window) {
+ window.destroy();
+ }
+ }
+
+ static GLWindow createWindow(String title, GLCapabilitiesImmutable caps, int width, int height) {
+ Assert.assertNotNull(caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setSize(width, height);
+ window.setPosition(10, 10);
+ window.setTitle(title);
+ Assert.assertNotNull(window);
+ window.setVisible(true);
+
+ return window;
+ }
+
+ @Test
+ public void testRegionRendererR2T01() throws InterruptedException {
+ GLProfile glp = GLProfile.getGL2ES2();
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ //caps.setOnscreen(false);
+ caps.setAlphaBits(4);
+
+ GLWindow window = createWindow("shape-r2t1-msaa0", caps, 800,400);
+
+ GPURegionGLListener02 demo02Listener = new GPURegionGLListener02 (Region.TWO_PASS, 1140, false, false);
+ demo02Listener.attachInputListenerTo(window);
+ window.addGLEventListener(demo02Listener);
+
+ RegionGLListener listener = new RegionGLListener(demo02Listener, window.getTitle(), "GPURegionNewtDemo02");
+ window.addGLEventListener(listener);
+
+ listener.setTech(-20, 00, 0f, -300, 400);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -150, 800);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -50, 1000);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ @Test
+ public void testRegionRendererMSAA01() throws InterruptedException {
+ GLProfile glp = GLProfile.get(GLProfile.GL2ES2);
+ GLCapabilities caps = new GLCapabilities(glp);
+ // caps.setOnscreen(false);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+
+ GLWindow window = createWindow("shape-r2t0-msaa1", caps, 800, 400);
+
+ GPURegionGLListener01 demo01Listener = new GPURegionGLListener01 (Region.SINGLE_PASS, 0, false, false);
+ demo01Listener.attachInputListenerTo(window);
+ window.addGLEventListener(demo01Listener);
+
+ RegionGLListener listener = new RegionGLListener(demo01Listener, window.getTitle(), "GPURegion01");
+ window.addGLEventListener(listener);
+
+ listener.setTech(-20, 00, 0f, -300, 400);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -150, 800);
+ window.display();
+
+ listener.setTech(-20, 00, 0f, -50, 1000);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ private class RegionGLListener implements GLEventListener {
+ String winTitle;
+ String name;
+ GPURegionRendererListenerBase01 impl;
+
+ public RegionGLListener(GPURegionRendererListenerBase01 impl, String title, String name) {
+ this.impl = impl;
+ this.winTitle = title;
+ this.name = name;
+ }
+
+ public void setTech(float xt, float yt, float angle, int zoom, int fboSize){
+ impl.setMatrix(xt, yt, angle, zoom, fboSize);
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ impl.init(drawable);
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ impl.display(drawable);
+
+ try {
+ impl.printScreen(drawable, "./", winTitle, name, false);
+ } catch (GLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ impl.dispose(drawable);
+
+ }
+
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ impl.reshape(drawable, x, y, width, height);
+
+ }
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java
new file mode 100755
index 000000000..c954c6aa7
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/TestTextRenderer01.java
@@ -0,0 +1,169 @@
+package com.jogamp.opengl.test.junit.graph;
+
+import java.io.IOException;
+
+import javax.media.nativewindow.NativeWindowFactory;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.geom.opengl.SVertex;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.graph.demos.GPUTextRendererListenerBase01;
+
+
+public class TestTextRenderer01 {
+
+ public static void main(String args[]) throws IOException {
+ String tstname = TestTextRenderer01.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+ @BeforeClass
+ public static void initClass() {
+ GLProfile.initSingleton(true);
+ NativeWindowFactory.initSingleton(true);
+ }
+
+ static void destroyWindow(GLWindow window) {
+ if(null!=window) {
+ window.destroy();
+ }
+ }
+
+ static GLWindow createWindow(String title, GLCapabilitiesImmutable caps, int width, int height) {
+ Assert.assertNotNull(caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setSize(width, height);
+ window.setPosition(10, 10);
+ window.setTitle(title);
+ Assert.assertNotNull(window);
+ window.setVisible(true);
+
+ return window;
+ }
+
+ @Test
+ public void testTextRendererR2T01() throws InterruptedException {
+ GLProfile glp = GLProfile.getGL2ES2();
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+
+ GLWindow window = createWindow("text-r2t1-msaa0", caps, 800,400);
+ TextGLListener textGLListener = new TextGLListener(Region.TWO_PASS);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ textGLListener.setFontSet(FontFactory.UBUNTU, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, window.getWidth()*2);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, window.getWidth()*3);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, window.getWidth()*4);
+ window.display();
+
+ textGLListener.setFontSet(FontFactory.JAVA, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, window.getWidth()*2);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, window.getWidth()*3);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, window.getWidth()*4);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ @Test
+ public void testTextRendererMSAA01() throws InterruptedException {
+ GLProfile glp = GLProfile.get(GLProfile.GL2ES2);
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+
+ GLWindow window = createWindow("text-r2t0-msaa1", caps, 800, 400);
+ TextGLListener textGLListener = new TextGLListener(Region.SINGLE_PASS);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ textGLListener.setFontSet(FontFactory.UBUNTU, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, 0);
+ window.display();
+
+ textGLListener.setFontSet(FontFactory.JAVA, 0, 0);
+ textGLListener.setTech(-400, -30, 0f, -1000, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -30, 0, -380, 0);
+ window.display();
+
+ textGLListener.setTech(-400, -20, 0, -80, 0);
+ window.display();
+
+ destroyWindow(window);
+ }
+
+ private class TextGLListener extends GPUTextRendererListenerBase01 {
+ String winTitle;
+
+ public TextGLListener(int type) {
+ super(SVertex.factory(), type, false, false);
+ }
+
+ public void attachInputListenerTo(GLWindow window) {
+ super.attachInputListenerTo(window);
+ winTitle = window.getTitle();
+ }
+ public void setTech(float xt, float yt, float angle, int zoom, int fboSize){
+ setMatrix(xt, yt, angle, zoom, fboSize);
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ super.init(drawable);
+ gl.setSwapInterval(1);
+ gl.glEnable(GL.GL_DEPTH_TEST);
+
+ final TextRenderer textRenderer = (TextRenderer) getRenderer();
+
+ textRenderer.init(gl);
+ textRenderer.setAlpha(gl, 1.0f);
+ textRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ super.display(drawable);
+
+ try {
+ printScreen(drawable, "./", winTitle, false);
+ } catch (GLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
new file mode 100644
index 000000000..bf4bfab71
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener01.java
@@ -0,0 +1,124 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+/** Demonstrate the rendering of multiple outlines into one region/OutlineShape
+ * These Outlines are not necessary connected or contained.
+ * The output of this demo shows two identical shapes but the left one
+ * has some vertices with off-curve flag set to true, and the right allt he vertices
+ * are on the curve. Demos the Res. Independent Nurbs based Curve rendering
+ *
+ */
+public class GPURegionGLListener01 extends GPURegionRendererListenerBase01 {
+ OutlineShape outlineShape = null;
+
+ public GPURegionGLListener01 (int numpass, int fbosize, boolean debug, boolean trace) {
+ super(SVertex.factory(), numpass, debug, trace);
+ setMatrix(-20, 00, 0f, -50, fbosize);
+ }
+
+ private void createTestOutline(){
+ float offset = 0;
+ outlineShape = new OutlineShape(getRenderer().getFactory());
+ outlineShape.addVertex(0.0f,-10.0f, true);
+ outlineShape.addVertex(15.0f,-10.0f, true);
+ outlineShape.addVertex(10.0f,5.0f, false);
+ outlineShape.addVertex(15.0f,10.0f, true);
+ outlineShape.addVertex(6.0f,15.0f, false);
+ outlineShape.addVertex(5.0f,8.0f, false);
+ outlineShape.addVertex(0.0f,10.0f,true);
+ outlineShape.closeLastOutline();
+ outlineShape.addEmptyOutline();
+ outlineShape.addVertex(5.0f,-5.0f,true);
+ outlineShape.addVertex(10.0f,-5.0f, false);
+ outlineShape.addVertex(10.0f,0.0f, true);
+ outlineShape.addVertex(5.0f,0.0f, false);
+ outlineShape.closeLastOutline();
+
+ /** Same shape as above but without any off-curve vertices */
+ outlineShape.addEmptyOutline();
+ offset = 30;
+ outlineShape.addVertex(offset+0.0f,-10.0f, true);
+ outlineShape.addVertex(offset+17.0f,-10.0f, true);
+ outlineShape.addVertex(offset+11.0f,5.0f, true);
+ outlineShape.addVertex(offset+16.0f,10.0f, true);
+ outlineShape.addVertex(offset+7.0f,15.0f, true);
+ outlineShape.addVertex(offset+6.0f,8.0f, true);
+ outlineShape.addVertex(offset+0.0f,10.0f, true);
+ outlineShape.closeLastOutline();
+ outlineShape.addEmptyOutline();
+ outlineShape.addVertex(offset+5.0f,0.0f, true);
+ outlineShape.addVertex(offset+5.0f,-5.0f, true);
+ outlineShape.addVertex(offset+10.0f,-5.0f, true);
+ outlineShape.addVertex(offset+10.0f,0.0f, true);
+ outlineShape.closeLastOutline();
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ super.init(drawable);
+
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ regionRenderer.init(gl);
+ regionRenderer.setAlpha(gl, 1.0f);
+ regionRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ //gl.glSampleCoverage(0.95f, false);
+ //gl.glEnable(GL2GL3.GL_SAMPLE_COVERAGE); // sample coverage doesn't really make a difference to lines
+ //gl.glEnable(GL2GL3.GL_SAMPLE_ALPHA_TO_ONE);
+ MSAATool.dump(drawable);
+
+ createTestOutline();
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ regionRenderer.resetModelview(null);
+ regionRenderer.translate(null, getXTran(), getYTran(), getZoom());
+ regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
+
+ regionRenderer.renderOutlineShape(gl, outlineShape, getPosition(), getTexSize());
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
new file mode 100644
index 000000000..56db37ebe
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionGLListener02.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+/** Demonstrate the rendering of multiple OutlineShapes
+ * into one region
+ *
+ */
+public class GPURegionGLListener02 extends GPURegionRendererListenerBase01 {
+ OutlineShape[] outlineShapes = new OutlineShape[2];
+
+ public GPURegionGLListener02 (int numpass, int fbosize, boolean debug, boolean trace) {
+ super(SVertex.factory(), numpass, debug, trace);
+ setMatrix(-20, 00, 0f, -50, fbosize);
+ }
+
+ private void createTestOutline(){
+ float offset = 0;
+ outlineShapes[0] = new OutlineShape(SVertex.factory());
+ outlineShapes[0].addVertex(0.0f,-10.0f,true);
+ outlineShapes[0].addVertex(15.0f,-10.0f, true);
+ outlineShapes[0].addVertex(10.0f,5.0f, false);
+ outlineShapes[0].addVertex(15.0f,10.0f, true);
+ outlineShapes[0].addVertex(6.0f,15.0f, false);
+ outlineShapes[0].addVertex(5.0f,8.0f, false);
+ outlineShapes[0].addVertex(0.0f,10.0f,true);
+ outlineShapes[0].closeLastOutline();
+ outlineShapes[0].addEmptyOutline();
+ outlineShapes[0].addVertex(5.0f,-5.0f,true);
+ outlineShapes[0].addVertex(10.0f,-5.0f, false);
+ outlineShapes[0].addVertex(10.0f,0.0f, true);
+ outlineShapes[0].addVertex(5.0f,0.0f, false);
+ outlineShapes[0].closeLastOutline();
+
+ /** Same shape as above but without any off-curve vertices */
+ outlineShapes[1] = new OutlineShape(SVertex.factory());
+ offset = 30;
+ outlineShapes[1].addVertex(offset+0.0f,-10.0f, true);
+ outlineShapes[1].addVertex(offset+17.0f,-10.0f, true);
+ outlineShapes[1].addVertex(offset+11.0f,5.0f, true);
+ outlineShapes[1].addVertex(offset+16.0f,10.0f, true);
+ outlineShapes[1].addVertex(offset+7.0f,15.0f, true);
+ outlineShapes[1].addVertex(offset+6.0f,8.0f, true);
+ outlineShapes[1].addVertex(offset+0.0f,10.0f, true);
+ outlineShapes[1].closeLastOutline();
+ outlineShapes[1].addEmptyOutline();
+ outlineShapes[1].addVertex(offset+5.0f,0.0f, true);
+ outlineShapes[1].addVertex(offset+5.0f,-5.0f, true);
+ outlineShapes[1].addVertex(offset+10.0f,-5.0f, true);
+ outlineShapes[1].addVertex(offset+10.0f,0.0f, true);
+ outlineShapes[1].closeLastOutline();
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ super.init(drawable);
+
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ regionRenderer.init(gl);
+ regionRenderer.setAlpha(gl, 1.0f);
+ regionRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ MSAATool.dump(drawable);
+
+ createTestOutline();
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final RegionRenderer regionRenderer = (RegionRenderer) getRenderer();
+
+ regionRenderer.resetModelview(null);
+ regionRenderer.translate(null, getXTran(), getYTran(), getZoom());
+ regionRenderer.rotate(gl, getAngle(), 0, 1, 0);
+
+ regionRenderer.renderOutlineShapes(gl, outlineShapes, getPosition(), getTexSize());
+
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java
new file mode 100755
index 000000000..dbd5fe158
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo01.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+/** Demonstrate the rendering of multiple outlines into one region/OutlineShape
+ * These Outlines are not necessary connected or contained.
+ * The output of this demo shows two identical shapes but the left one
+ * has some vertices with off-curve flag set to true, and the right allt he vertices
+ * are on the curve. Demos the Res. Independent Nurbs based Curve rendering
+ *
+ */
+public class GPURegionNewtDemo01 {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4); // 2 samples is not enough ..
+ System.out.println("Requested: " + caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Curve Region Newt Demo 01 - r2t0 msaa1");
+
+ GPURegionGLListener01 regionGLListener = new GPURegionGLListener01 (Region.SINGLE_PASS, 0, DEBUG, TRACE);
+ regionGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(regionGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+
+ //FPSAnimator animator = new FPSAnimator(60);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java
new file mode 100644
index 000000000..7ffab59e3
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionNewtDemo02.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+/** Demonstrate the rendering of multiple OutlineShapes
+ * into one region
+ *
+ */
+public class GPURegionNewtDemo02 {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GPURegionNewtDemo02 test = new GPURegionNewtDemo02();
+ test.testMe();
+ }
+
+ public void testMe() {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ System.out.println("Requested: " + caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Curve Region Newt Demo 02 - r2t1 msaa0");
+
+ GPURegionGLListener02 regionGLListener = new GPURegionGLListener02 (Region.TWO_PASS, 1140, DEBUG, TRACE);
+ regionGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(regionGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+
+ //FPSAnimator animator = new FPSAnimator(60);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java
new file mode 100644
index 000000000..eab5fc8eb
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURegionRendererListenerBase01.java
@@ -0,0 +1,52 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.curve.opengl.RegionRenderer;
+import com.jogamp.graph.geom.Vertex;
+
+/**
+ *
+ * Action Keys:
+ * - 1/2: zoom in/out
+ * - 3/4: font +/-
+ * - 6/7: 2nd pass texture size
+ * - 0/9: rotate
+ * - s: toogle draw 'font set'
+ * - f: toggle draw fps
+ * - v: toggle v-sync
+ * - space: toggle font (ubuntu/java)
+ */
+public abstract class GPURegionRendererListenerBase01 extends GPURendererListenerBase01 {
+ OutlineShape outlineShape = null;
+
+ public GPURegionRendererListenerBase01(Vertex.Factory<? extends Vertex> factory, int mode, boolean debug, boolean trace) {
+ super(RegionRenderer.create(factory, mode), debug, trace);
+ }
+} \ No newline at end of file
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
new file mode 100644
index 000000000..622178bf2
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPURendererListenerBase01.java
@@ -0,0 +1,264 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLPipelineFactory;
+import javax.media.opengl.GLRunnable;
+
+import com.jogamp.graph.curve.opengl.Renderer;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.opengl.GLWindow;
+
+/**
+ *
+ * Action Keys:
+ * - 1/2: zoom in/out
+ * - 6/7: 2nd pass texture size
+ * - 0/9: rotate
+ * - v: toggle v-sync
+ * - s: screenshot
+ */
+public abstract class GPURendererListenerBase01 implements GLEventListener {
+ private Screenshot screenshot;
+ private Renderer renderer;
+ private boolean debug;
+ private boolean trace;
+
+ private KeyAction keyAction;
+
+ private volatile GLAutoDrawable autoDrawable = null;
+
+ private final float[] position = new float[] {0,0,0};
+
+ private float xTran = -10;
+ private float yTran = 10;
+ private float ang = 0f;
+ private float zoom = -70f;
+ private int texSize = 400;
+
+ boolean updateMatrix = true;
+ boolean ignoreInput = false;
+
+ public GPURendererListenerBase01(Renderer renderer, boolean debug, boolean trace) {
+ this.renderer = renderer;
+ this.debug = debug;
+ this.trace = trace;
+ this.screenshot = new Screenshot();
+ }
+
+ public final Renderer getRenderer() { return renderer; }
+ public final float getZoom() { return zoom; }
+ public final float getXTran() { return xTran; }
+ public final float getYTran() { return yTran; }
+ public final float getAngle() { return ang; }
+ public final int getTexSize() { return texSize; }
+ public final float[] getPosition() { return position; }
+
+ public void setMatrix(float xtrans, float ytrans, float angle, int zoom, int fbosize) {
+ this.xTran = xtrans;
+ this.yTran = ytrans;
+ this.ang = angle;
+ this.zoom = zoom;
+ this.texSize = fbosize;
+ updateMatrix = true;
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ autoDrawable = drawable;
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ if(debug) {
+ gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, gl, null) ).getGL2ES2();
+ }
+ if(trace) {
+ gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ).getGL2ES2();
+ }
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ }
+
+ public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glViewport(xstart, ystart, width, height);
+ renderer.reshapePerspective(gl, 45.0f, width, height, 0.1f, 7000.0f);
+
+ dumpMatrix();
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ autoDrawable = null;
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ screenshot.dispose();
+ renderer.dispose(gl);
+ }
+
+ public void zoom(int v){
+ zoom += v;
+ updateMatrix = true;
+ dumpMatrix();
+ }
+
+ public void move(float x, float y){
+ xTran += x;
+ yTran += y;
+ updateMatrix = true;
+ dumpMatrix();
+ }
+ public void rotate(float delta){
+ ang += delta;
+ ang %= 360.0f;
+ updateMatrix = true;
+ dumpMatrix();
+ }
+
+ void dumpMatrix() {
+ System.err.println("Matrix: " + xTran + "/" + yTran + " x"+zoom + " @"+ang);
+ }
+
+ /** Attach the input listener to the window */
+ public void attachInputListenerTo(GLWindow window) {
+ if ( null == keyAction ) {
+ keyAction = new KeyAction();
+ window.addKeyListener(keyAction);
+ }
+ }
+
+ public void detachFrom(GLWindow window) {
+ if ( null == keyAction ) {
+ return;
+ }
+ window.removeGLEventListener(this);
+ window.removeKeyListener(keyAction);
+ }
+
+ public void printScreen(GLAutoDrawable drawable, String dir, String tech, String objName, boolean exportAlpha) throws GLException, IOException {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ pw.printf("-%03dx%03d-Z%04d-T%04d-%s", drawable.getWidth(), drawable.getHeight(), (int)Math.abs(zoom), texSize, objName);
+
+ String filename = dir + tech + sw +".tga";
+ screenshot.surface2File(drawable, filename /*, exportAlpha */);
+ }
+
+ int screenshot_num = 0;
+
+ public void setIgnoreInput(boolean v) {
+ ignoreInput = v;
+ }
+ public boolean getIgnoreInput() {
+ return ignoreInput;
+ }
+
+ public class KeyAction implements KeyListener {
+ public void keyPressed(KeyEvent arg0) {
+ if(ignoreInput) {
+ return;
+ }
+
+ if(arg0.getKeyCode() == KeyEvent.VK_1){
+ zoom(10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_2){
+ zoom(-10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_UP){
+ move(0, -1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
+ move(0, 1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
+ move(1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
+ move(-1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_6){
+ texSize -= 10;
+ System.err.println("Tex Size: " + texSize);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_7){
+ texSize += 10;
+ System.err.println("Tex Size: " + texSize);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_0){
+ rotate(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_9){
+ rotate(-1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_V) {
+ if(null != autoDrawable) {
+ autoDrawable.invoke(false, new GLRunnable() {
+ public void run(GLAutoDrawable drawable) {
+ GL gl = drawable.getGL();
+ int i = gl.getSwapInterval();
+ i = i==0 ? 1 : 0;
+ gl.setSwapInterval(i);
+ final GLAnimatorControl a = drawable.getAnimator();
+ if( null != a ) {
+ a.resetCounter();
+ }
+ System.err.println("Swap Interval: "+i);
+ }
+ });
+ }
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_S){
+ rotate(-1);
+ if(null != autoDrawable) {
+ autoDrawable.invoke(false, new GLRunnable() {
+ public void run(GLAutoDrawable drawable) {
+ try {
+ final String type = ( 1 == renderer.getRenderType() ) ? "r2t0-msaa1" : "r2t1-msaa0" ;
+ printScreen(drawable, "./", "demo-"+type, "snap"+screenshot_num, false);
+ screenshot_num++;
+ } catch (GLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {}
+ public void keyReleased(KeyEvent arg0) {}
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java
new file mode 100644
index 000000000..7290246d1
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextGLListener0A.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.geom.opengl.SVertex;
+
+public class GPUTextGLListener0A extends GPUTextRendererListenerBase01 {
+ public GPUTextGLListener0A(int numpass, int fbosize, boolean debug, boolean trace) {
+ super(SVertex.factory(), numpass, debug, trace);
+ setMatrix(-400, -30, 0f, -500, fbosize);
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ super.init(drawable);
+
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ final TextRenderer textRenderer = (TextRenderer) getRenderer();
+
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ textRenderer.init(gl);
+ textRenderer.setAlpha(gl, 1.0f);
+ textRenderer.setColor(gl, 0.0f, 0.0f, 0.0f);
+ //gl.glSampleCoverage(0.95f, false);
+ //gl.glEnable(GL2GL3.GL_SAMPLE_COVERAGE); // sample coverage doesn't really make a difference to lines
+ //gl.glEnable(GL2GL3.GL_SAMPLE_ALPHA_TO_COVERAGE);
+ //gl.glEnable(GL2GL3.GL_SAMPLE_ALPHA_TO_ONE);
+ MSAATool.dump(drawable);
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java
new file mode 100644
index 000000000..3739f28ea
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo01.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+public class GPUTextNewtDemo01 {
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4); // 2 samples is not enough ..
+ System.out.println("Requested: "+caps);
+
+ GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Text Newt Demo 01 - r2t0 msaa1");
+
+ GPUTextGLListener0A textGLListener = new GPUTextGLListener0A(Region.SINGLE_PASS, 0, DEBUG, TRACE);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+ // FPSAnimator animator = new FPSAnimator(10);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java
new file mode 100644
index 000000000..40c7d6ac4
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextNewtDemo02.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.Animator;
+
+public class GPUTextNewtDemo02 {
+ /**
+ * FIXME:
+ *
+ * If DEBUG is enabled:
+ *
+ * Caused by: javax.media.opengl.GLException: Thread[main-Display-X11_:0.0-1-EDT-1,5,main] glGetError() returned the following error codes after a call to glFramebufferRenderbuffer(<int> 0x8D40, <int> 0x1902, <int> 0x8D41, <int> 0x1): GL_INVALID_ENUM ( 1280 0x500),
+ * at javax.media.opengl.DebugGL4bc.checkGLGetError(DebugGL4bc.java:33961)
+ * at javax.media.opengl.DebugGL4bc.glFramebufferRenderbuffer(DebugGL4bc.java:33077)
+ * at jogamp.graph.curve.opengl.VBORegion2PGL3.initFBOTexture(VBORegion2PGL3.java:295)
+ */
+ static final boolean DEBUG = false;
+ static final boolean TRACE = false;
+
+ public static void main(String[] args) {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ System.out.println("Requested: "+caps);
+
+ GLWindow window = GLWindow.create(caps);
+
+ window.setPosition(10, 10);
+ window.setSize(800, 400);
+ window.setTitle("GPU Text Newt Demo 02 - r2t1 msaa0");
+
+ GPUTextGLListener0A textGLListener = new GPUTextGLListener0A(Region.TWO_PASS, window.getWidth()*3, DEBUG, TRACE);
+ textGLListener.attachInputListenerTo(window);
+ window.addGLEventListener(textGLListener);
+
+ window.enablePerfLog(true);
+ window.setVisible(true);
+ // FPSAnimator animator = new FPSAnimator(60);
+ Animator animator = new Animator();
+ animator.add(window);
+ animator.start();
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
new file mode 100644
index 000000000..909f68b85
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/GPUTextRendererListenerBase01.java
@@ -0,0 +1,229 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import java.io.IOException;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAnimatorControl;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLException;
+import com.jogamp.graph.curve.opengl.TextRenderer;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.geom.AABBox;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.opengl.GLWindow;
+
+/**
+ *
+ * GPURendererListenerBase01 Keys:
+ * - 1/2: zoom in/out
+ * - 6/7: 2nd pass texture size
+ * - 0/9: rotate
+ * - v: toggle v-sync
+ * - s: screenshot
+ *
+ * Additional Keys:
+ * - 3/4: font +/-
+ * - h: toogle draw 'font set'
+ * - f: toggle draw fps
+ * - space: toggle font (ubuntu/java)
+ * - i: live input text input (CR ends it, backspace supported)
+ */
+public abstract class GPUTextRendererListenerBase01 extends GPURendererListenerBase01 {
+ int fontSet = FontFactory.UBUNTU;
+ Font font;
+
+ boolean drawFontSet = true;
+ boolean drawFPS = true;
+ boolean updateFont = true;
+ int fontSize = 40;
+ final int fontSizeModulo = 100;
+
+ static final String text1 = "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n0123456789.:,;(*!?/\\\")$%^&-+@~#<>{}[]";
+ static final String text2 = "The quick brown fox jumps over the lazy dog";
+
+ StringBuffer userString = new StringBuffer();
+ boolean userInput = false;
+
+ public GPUTextRendererListenerBase01(Vertex.Factory<? extends Vertex> factory, int mode, boolean debug, boolean trace) {
+ super(TextRenderer.create(factory, mode), debug, trace);
+ this.font = FontFactory.get(fontSet).getDefault();
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Demo02 needs to have this set here as well .. hmm ?
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final TextRenderer textRenderer = (TextRenderer) getRenderer();
+
+ if(drawFPS || drawFontSet || updateMatrix) {
+ final int width = drawable.getWidth();
+ final int height = drawable.getHeight();
+ final GLAnimatorControl animator = drawable.getAnimator();
+ final boolean _drawFPS = drawFPS && null != animator && animator.getTotalFrames()>10;
+
+ if(_drawFPS || drawFontSet) {
+ textRenderer.reshapeOrtho(null, width, height, 0.1f, 7000.0f);
+ }
+ if(_drawFPS) {
+ final float fps = ( animator.getTotalFrames() * 1000.0f ) / (float) animator.getDuration() ;
+ final String fpsS = String.valueOf(fps);
+ final int fpsSp = fpsS.indexOf('.');
+ textRenderer.resetModelview(null);
+ textRenderer.translate(gl, 0, 0, -6000);
+ textRenderer.renderString3D(gl, font, fpsS.substring(0, fpsSp+2), getPosition(), fontSize, getTexSize());
+ }
+ if(drawFontSet) {
+ textRenderer.resetModelview(null);
+ final AABBox box = font.getStringBounds(font.getName(), fontSize/4);
+ final int dx = width-(int)box.getWidth()-2;
+ final int dy = height-(int)box.getHeight()-2;
+ textRenderer.translate(gl, dx, dy, -6000);
+ textRenderer.renderString3D(gl, font, font.getName(), getPosition(), fontSize/4, getTexSize());
+ textRenderer.translate(gl, -dx, -20, 0);
+ textRenderer.renderString3D(gl, font, text1, getPosition(), fontSize, getTexSize());
+ }
+ if(_drawFPS || drawFontSet) {
+ textRenderer.reshapePerspective(null, 45.0f, width, height, 0.1f, 7000.0f);
+ }
+
+ textRenderer.resetModelview(null);
+ textRenderer.translate(null, getXTran(), getYTran(), getZoom());
+ textRenderer.rotate(gl, getAngle(), 0, 1, 0);
+ updateMatrix = false;
+ }
+
+ if(!userInput) {
+ textRenderer.renderString3D(gl, font, text2, getPosition(), fontSize, getTexSize());
+ } else {
+ textRenderer.renderString3D(gl, font, userString.toString(), getPosition(), fontSize, getTexSize());
+ }
+ }
+
+ public void fontIncr(int v) {
+ fontSize = Math.abs((fontSize + v) % fontSizeModulo) ;
+ updateFont = true;
+ dumpMatrix(true);
+ }
+
+ public void nextFontSet() {
+ fontSet = ( fontSet == FontFactory.UBUNTU ) ? FontFactory.JAVA : FontFactory.UBUNTU ;
+ font = FontFactory.get(fontSet).getDefault();
+ }
+
+ public void setFontSet(int set, int family, int stylebits) {
+ fontSet = set;
+ font = FontFactory.get(fontSet).get(family, stylebits);
+ }
+
+ public boolean isUserInputMode() { return userInput; }
+
+ void dumpMatrix(boolean bbox) {
+ System.err.println("Matrix: " + getXTran() + "/" + getYTran() + " x"+getZoom() + " @"+getAngle() +" fontSize "+fontSize);
+ if(bbox) {
+ System.err.println("bbox: "+font.getStringBounds(text2, fontSize));
+ }
+ }
+
+ KeyAction keyAction = null;
+
+ @Override
+ public void attachInputListenerTo(GLWindow window) {
+ if ( null == keyAction ) {
+ keyAction = new KeyAction();
+ window.addKeyListener(keyAction);
+ super.attachInputListenerTo(window);
+ }
+
+ }
+
+ @Override
+ public void detachFrom(GLWindow window) {
+ super.detachFrom(window);
+ if ( null == keyAction ) {
+ return;
+ }
+ window.removeKeyListener(keyAction);
+ }
+
+ public void printScreen(GLAutoDrawable drawable, String dir, String tech, boolean exportAlpha) throws GLException, IOException {
+ printScreen(drawable, dir, tech, font.getName(), exportAlpha);
+ }
+
+ public class KeyAction implements KeyListener {
+ public void keyPressed(KeyEvent arg0) {
+ if(userInput) {
+ return;
+ }
+
+ if(arg0.getKeyCode() == KeyEvent.VK_3){
+ fontIncr(10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_4){
+ fontIncr(-10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_H) {
+ drawFontSet = !drawFontSet;
+ System.err.println("Draw font set: "+drawFontSet);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_F){
+ drawFPS = !drawFPS;
+ System.err.println("Draw FPS: "+drawFPS);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_SPACE) {
+ nextFontSet();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_I){
+ userInput = true;
+ setIgnoreInput(true);
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {
+ if(userInput) {
+ char c = arg0.getKeyChar();
+
+ System.err.println(arg0);
+ if(c == 0x08) {
+ userString.deleteCharAt(userString.length()-1);
+ } else if(c == 0x0d) {
+ userInput = false;
+ setIgnoreInput(true);
+ } else {
+ userString.append(c);
+ }
+ }
+ }
+ public void keyReleased(KeyEvent arg0) {}
+ }
+} \ No newline at end of file
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java
new file mode 100644
index 000000000..5975e096b
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/MSAATool.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL2GL3;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilitiesImmutable;
+
+public class MSAATool {
+ public static void dump(GLAutoDrawable drawable) {
+ float[] vf = new float[] { 0f };
+ byte[] vb = new byte[] { 0 };
+ int[] vi = new int[] { 0, 0 };
+
+ System.out.println("GL MSAA SETUP:");
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ GLCapabilitiesImmutable caps = drawable.getChosenGLCapabilities();
+ System.out.println(" Caps realised "+caps);
+ System.out.println(" Caps sample buffers "+caps.getSampleBuffers()+", samples "+caps.getNumSamples());
+
+ // default TRUE
+ System.out.println(" GL MULTISAMPLE "+gl.glIsEnabled(GL2ES2.GL_MULTISAMPLE));
+ // sample buffers min 0, same as GLX_SAMPLE_BUFFERS_ARB or WGL_SAMPLE_BUFFERS_ARB
+ gl.glGetIntegerv(GL2GL3.GL_SAMPLE_BUFFERS, vi, 0);
+ // samples min 0
+ gl.glGetIntegerv(GL2GL3.GL_SAMPLES, vi, 1);
+ System.out.println(" GL SAMPLE_BUFFERS "+vi[0]+", SAMPLES "+vi[1]);
+
+ System.out.println("GL CSAA SETUP:");
+ // default FALSE
+ System.out.println(" GL SAMPLE COVERAGE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_COVERAGE));
+ // default FALSE
+ System.out.println(" GL SAMPLE_ALPHA_TO_COVERAGE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_ALPHA_TO_COVERAGE));
+ // default FALSE
+ System.out.println(" GL SAMPLE_ALPHA_TO_ONE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_ALPHA_TO_ONE));
+ // default FALSE, value 1, invert false
+ gl.glGetFloatv(GL2GL3.GL_SAMPLE_COVERAGE_VALUE, vf, 0);
+ gl.glGetBooleanv(GL2GL3.GL_SAMPLE_COVERAGE_INVERT, vb, 0);
+ System.out.println(" GL SAMPLE_COVERAGE "+gl.glIsEnabled(GL2GL3.GL_SAMPLE_COVERAGE) +
+ ": SAMPLE_COVERAGE_VALUE "+vf[0]+
+ ", SAMPLE_COVERAGE_INVERT "+vb[0]);
+ }
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java
new file mode 100644
index 000000000..172eef4fc
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/ReadBufferUtil.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright 2010 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 com.jogamp.opengl.test.junit.graph.demos;
+
+import com.jogamp.opengl.util.GLBuffers;
+import java.nio.*;
+import javax.media.opengl.*;
+
+import com.jogamp.opengl.util.texture.Texture;
+import com.jogamp.opengl.util.texture.TextureData;
+
+public class ReadBufferUtil {
+ protected int readPixelSizeLast = 0;
+ protected Buffer readPixelBuffer = null;
+ protected TextureData readTextureData = null;
+ protected Texture readTexture = new Texture(GL.GL_TEXTURE_2D);
+
+ public Buffer getPixelBuffer() { return readPixelBuffer; }
+ public void rewindPixelBuffer() { readPixelBuffer.rewind(); }
+
+ public TextureData getTextureData() { return readTextureData; }
+ public Texture getTexture() { return readTexture; }
+
+ public boolean isValid() {
+ return null!=readTexture && null!=readTextureData && null!=readPixelBuffer ;
+ }
+
+ public void fetchOffscreenTexture(GLDrawable drawable, GL gl) {
+ int readPixelSize = drawable.getWidth() * drawable.getHeight() * 3 ; // RGB
+ boolean newData = false;
+ if(readPixelSize>readPixelSizeLast) {
+ readPixelBuffer = GLBuffers.newDirectGLBuffer(GL.GL_UNSIGNED_BYTE, readPixelSize);
+ readPixelSizeLast = readPixelSize ;
+ try {
+ readTextureData = new TextureData(
+ gl.getGLProfile(),
+ // gl.isGL2GL3()?gl.GL_RGBA:gl.GL_RGB,
+ GL.GL_RGB,
+ drawable.getWidth(), drawable.getHeight(),
+ 0,
+ GL.GL_RGB,
+ GL.GL_UNSIGNED_BYTE,
+ false, false,
+ false /* flip */,
+ readPixelBuffer,
+ null /* Flusher */);
+ newData = true;
+ } catch (Exception e) {
+ readTextureData = null;
+ readPixelBuffer = null;
+ readPixelSizeLast = 0;
+ throw new RuntimeException("can not fetch offscreen texture", e);
+ }
+ }
+ if(null!=readPixelBuffer) {
+ readPixelBuffer.clear();
+ gl.glReadPixels(0, 0, drawable.getWidth(), drawable.getHeight(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE, readPixelBuffer);
+ readPixelBuffer.rewind();
+ if(newData) {
+ readTexture.updateImage(readTextureData);
+ } else {
+ readTexture.updateSubImage(readTextureData, 0,
+ 0, 0, // src offset
+ 0, 0, // dst offset
+ drawable.getWidth(), drawable.getHeight());
+ }
+ readPixelBuffer.rewind();
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void dispose() {
+ readTexture.dispose();
+ readTextureData = null;
+ if(null != readPixelBuffer) {
+ readPixelBuffer.clear();
+ readPixelBuffer = null;
+ }
+ readPixelSizeLast = 0;
+ }
+
+}
+
diff --git a/src/test/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java b/src/test/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java
new file mode 100644
index 000000000..e0c304e49
--- /dev/null
+++ b/src/test/com/jogamp/opengl/test/junit/graph/demos/Screenshot.java
@@ -0,0 +1,39 @@
+package com.jogamp.opengl.test.junit.graph.demos;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GLAutoDrawable;
+
+import com.jogamp.opengl.util.texture.TextureIO;
+
+public class Screenshot {
+
+ ReadBufferUtil readBufferUtil = new ReadBufferUtil();
+
+ public void dispose() {
+ readBufferUtil.dispose();
+ }
+
+ public void surface2File(GLAutoDrawable drawable, String filename) {
+ GL gl = drawable.getGL();
+ // FIXME glFinish() is an expensive paranoia sync, should not be necessary due to spec
+ gl.glFinish();
+ readBufferUtil.fetchOffscreenTexture(drawable, gl);
+ gl.glFinish();
+ try {
+ surface2File(filename);
+ } catch (IOException ex) {
+ throw new RuntimeException("can not write survace to file", ex);
+ }
+ }
+
+ void surface2File(String filename) throws IOException {
+ File file = new File(filename);
+ TextureIO.write(readBufferUtil.getTextureData(), file);
+ System.err.println("Wrote: " + file.getAbsolutePath() + ", ...");
+ readBufferUtil.rewindPixelBuffer();
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/Disassembler.java b/src/typecast/net/java/dev/typecast/ot/Disassembler.java
new file mode 100644
index 000000000..73e75cc39
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/Disassembler.java
@@ -0,0 +1,109 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot;
+
+/**
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Disassembler.java,v 1.1.1.1 2004-12-05 23:14:25 davidsch Exp $
+ */
+public class Disassembler {
+
+ /**
+ * Advance the instruction pointer to the next executable opcode.
+ * This will be the next byte, unless the current opcode is a push
+ * instruction, in which case it will be the byte immediately beyond
+ * the last data byte.
+ * @param ip The current instruction pointer
+ * @return The new instruction pointer
+ */
+ public static int advanceIP(short[] instructions, int ip) {
+
+ // The high word specifies font, cvt, or glyph program
+ int i = ip & 0xffff;
+ int dataCount;
+ ip++;
+ if (Mnemonic.NPUSHB == instructions[i]) {
+ // Next byte is the data byte count
+ dataCount = instructions[++i];
+ ip += dataCount + 1;
+ } else if (Mnemonic.NPUSHW == instructions[i]) {
+ // Next byte is the data word count
+ dataCount = instructions[++i];
+ ip += dataCount*2 + 1;
+ } else if (Mnemonic.PUSHB == (instructions[i] & 0xf8)) {
+ dataCount = (short)((instructions[i] & 0x07) + 1);
+ ip += dataCount;
+ } else if (Mnemonic.PUSHW == (instructions[i] & 0xf8)) {
+ dataCount = (short)((instructions[i] & 0x07) + 1);
+ ip += dataCount*2;
+ }
+ return ip;
+ }
+
+ public static short getPushCount(short[] instructions, int ip) {
+ short instr = instructions[ip & 0xffff];
+ if ((Mnemonic.NPUSHB == instr) || (Mnemonic.NPUSHW == instr)) {
+ return instructions[(ip & 0xffff) + 1];
+ } else if ((Mnemonic.PUSHB == (instr & 0xf8)) || (Mnemonic.PUSHW == (instr & 0xf8))) {
+ return (short)((instr & 0x07) + 1);
+ }
+ return 0;
+ }
+
+ public static int[] getPushData(short[] instructions, int ip) {
+ int count = getPushCount(instructions, ip);
+ int[] data = new int[count];
+ int i = ip & 0xffff;
+ short instr = instructions[i];
+ if (Mnemonic.NPUSHB == instr) {
+ for (int j = 0; j < count; j++) {
+ data[j] = instructions[i + j + 2];
+ }
+ } else if (Mnemonic.PUSHB == (instr & 0xf8)) {
+ for (int j = 0; j < count; j++) {
+ data[j] = instructions[i + j + 1];
+ }
+ } else if (Mnemonic.NPUSHW == instr) {
+ for (int j = 0; j < count; j++) {
+ data[j] = (instructions[i + j*2 + 2] << 8) | instructions[i + j*2 + 3];
+ }
+ } else if (Mnemonic.PUSHW == (instr & 0xf8)) {
+ for (int j = 0; j < count; j++) {
+ data[j] = (instructions[i + j*2 + 1] << 8) | instructions[i + j*2 + 2];
+ }
+ }
+ return data;
+ }
+
+ public static String disassemble(short[] instructions, int leadingSpaces) {
+ StringBuffer sb = new StringBuffer();
+ int ip = 0;
+ while (ip < instructions.length) {
+ for (int i = 0; i < leadingSpaces; i++) {
+ sb.append(" ");
+ }
+ sb.append(ip).append(": ");
+ sb.append(Mnemonic.getMnemonic(instructions[ip]));
+ if (getPushCount(instructions, ip) > 0) {
+ int[] data = getPushData(instructions, ip);
+ for(int j = 0; j < data.length; j++) {
+ if ((instructions[ip] == Mnemonic.PUSHW) ||
+ (instructions[ip] == Mnemonic.NPUSHW)) {
+ sb.append(" ").append((short) data[j]);
+ } else {
+ sb.append(" ").append(data[j]);
+ }
+ }
+ }
+ sb.append("\n");
+ ip = advanceIP(instructions, ip);
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/Fixed.java b/src/typecast/net/java/dev/typecast/ot/Fixed.java
new file mode 100644
index 000000000..6f83e922c
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/Fixed.java
@@ -0,0 +1,852 @@
+/*
+ * $Id: Fixed.java,v 1.1.1.1 2004-12-05 23:14:26 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot;
+
+/**
+ * Functions for working with signed 16.16 fixed values
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Fixed.java,v 1.1.1.1 2004-12-05 23:14:26 davidsch Exp $
+ */
+public class Fixed {
+
+ // Tangent LUT
+ static private int[] t = {
+ 0x0,
+ 0x1,
+ 0x3,
+ 0x4,
+ 0x6,
+ 0x7,
+ 0x9,
+ 0xb,
+ 0xc,
+ 0xe,
+ 0xf,
+ 0x11,
+ 0x12,
+ 0x14,
+ 0x16,
+ 0x17,
+ 0x19,
+ 0x1a,
+ 0x1c,
+ 0x1d,
+ 0x1f,
+ 0x21,
+ 0x22,
+ 0x24,
+ 0x25,
+ 0x27,
+ 0x29,
+ 0x2a,
+ 0x2c,
+ 0x2e,
+ 0x2f,
+ 0x31,
+ 0x32,
+ 0x34,
+ 0x36,
+ 0x37,
+ 0x39,
+ 0x3b,
+ 0x3c,
+ 0x3e,
+ 0x40,
+ 0x41,
+ 0x43,
+ 0x45,
+ 0x46,
+ 0x48,
+ 0x4a,
+ 0x4b,
+ 0x4d,
+ 0x4f,
+ 0x51,
+ 0x52,
+ 0x54,
+ 0x56,
+ 0x58,
+ 0x59,
+ 0x5b,
+ 0x5d,
+ 0x5f,
+ 0x60,
+ 0x62,
+ 0x64,
+ 0x66,
+ 0x68,
+ 0x6a,
+ 0x6b,
+ 0x6d,
+ 0x6f,
+ 0x71,
+ 0x73,
+ 0x75,
+ 0x77,
+ 0x79,
+ 0x7b,
+ 0x7c,
+ 0x7e,
+ 0x80,
+ 0x82,
+ 0x84,
+ 0x86,
+ 0x88,
+ 0x8a,
+ 0x8c,
+ 0x8e,
+ 0x91,
+ 0x93,
+ 0x95,
+ 0x97,
+ 0x99,
+ 0x9b,
+ 0x9d,
+ 0x9f,
+ 0xa2,
+ 0xa4,
+ 0xa6,
+ 0xa8,
+ 0xab,
+ 0xad,
+ 0xaf,
+ 0xb1,
+ 0xb4,
+ 0xb6,
+ 0xb9,
+ 0xbb,
+ 0xbd,
+ 0xc0,
+ 0xc2,
+ 0xc5,
+ 0xc7,
+ 0xca,
+ 0xcc,
+ 0xcf,
+ 0xd2,
+ 0xd4,
+ 0xd7,
+ 0xda,
+ 0xdc,
+ 0xdf,
+ 0xe2,
+ 0xe5,
+ 0xe8,
+ 0xea,
+ 0xed,
+ 0xf0,
+ 0xf3,
+ 0xf6,
+ 0xf9,
+ 0xfc,
+ 0x100,
+ 0x103,
+ 0x106,
+ 0x109,
+ 0x10c,
+ 0x110,
+ 0x113,
+ 0x116,
+ 0x11a,
+ 0x11d,
+ 0x121,
+ 0x125,
+ 0x128,
+ 0x12c,
+ 0x130,
+ 0x134,
+ 0x137,
+ 0x13b,
+ 0x13f,
+ 0x143,
+ 0x148,
+ 0x14c,
+ 0x150,
+ 0x154,
+ 0x159,
+ 0x15d,
+ 0x162,
+ 0x166,
+ 0x16b,
+ 0x170,
+ 0x175,
+ 0x17a,
+ 0x17f,
+ 0x184,
+ 0x189,
+ 0x18e,
+ 0x194,
+ 0x199,
+ 0x19f,
+ 0x1a5,
+ 0x1ab,
+ 0x1b1,
+ 0x1b7,
+ 0x1bd,
+ 0x1c3,
+ 0x1ca,
+ 0x1d1,
+ 0x1d7,
+ 0x1de,
+ 0x1e6,
+ 0x1ed,
+ 0x1f4,
+ 0x1fc,
+ 0x204,
+ 0x20c,
+ 0x214,
+ 0x21d,
+ 0x225,
+ 0x22e,
+ 0x238,
+ 0x241,
+ 0x24b,
+ 0x255,
+ 0x25f,
+ 0x26a,
+ 0x274,
+ 0x280,
+ 0x28b,
+ 0x297,
+ 0x2a3,
+ 0x2b0,
+ 0x2bd,
+ 0x2cb,
+ 0x2d9,
+ 0x2e8,
+ 0x2f7,
+ 0x306,
+ 0x317,
+ 0x328,
+ 0x339,
+ 0x34b,
+ 0x35e,
+ 0x372,
+ 0x387,
+ 0x39d,
+ 0x3b3,
+ 0x3cb,
+ 0x3e4,
+ 0x3fe,
+ 0x419,
+ 0x435,
+ 0x454,
+ 0x474,
+ 0x495,
+ 0x4b9,
+ 0x4de,
+ 0x506,
+ 0x531,
+ 0x55e,
+ 0x58f,
+ 0x5c3,
+ 0x5fb,
+ 0x637,
+ 0x677,
+ 0x6bd,
+ 0x709,
+ 0x75c,
+ 0x7b7,
+ 0x81b,
+ 0x889,
+ 0x904,
+ 0x98d,
+ 0xa27,
+ 0xad5,
+ 0xb9c,
+ 0xc82,
+ 0xd8e,
+ 0xecb,
+ 0x1046,
+ 0x1217,
+ 0x145a,
+ 0x1744,
+ 0x1b26,
+ 0x2095,
+ 0x28bc,
+ 0x3651,
+ 0x517b,
+ 0xa2f8
+ };
+
+ // Sine LUT
+ static private int[] s = {
+ 0x0,
+ 0x1,
+ 0x3,
+ 0x4,
+ 0x6,
+ 0x7,
+ 0x9,
+ 0xa,
+ 0xc,
+ 0xe,
+ 0xf,
+ 0x11,
+ 0x12,
+ 0x14,
+ 0x15,
+ 0x17,
+ 0x19,
+ 0x1a,
+ 0x1c,
+ 0x1d,
+ 0x1f,
+ 0x20,
+ 0x22,
+ 0x24,
+ 0x25,
+ 0x27,
+ 0x28,
+ 0x2a,
+ 0x2b,
+ 0x2d,
+ 0x2e,
+ 0x30,
+ 0x31,
+ 0x33,
+ 0x35,
+ 0x36,
+ 0x38,
+ 0x39,
+ 0x3b,
+ 0x3c,
+ 0x3e,
+ 0x3f,
+ 0x41,
+ 0x42,
+ 0x44,
+ 0x45,
+ 0x47,
+ 0x48,
+ 0x4a,
+ 0x4b,
+ 0x4d,
+ 0x4e,
+ 0x50,
+ 0x51,
+ 0x53,
+ 0x54,
+ 0x56,
+ 0x57,
+ 0x59,
+ 0x5a,
+ 0x5c,
+ 0x5d,
+ 0x5f,
+ 0x60,
+ 0x61,
+ 0x63,
+ 0x64,
+ 0x66,
+ 0x67,
+ 0x69,
+ 0x6a,
+ 0x6c,
+ 0x6d,
+ 0x6e,
+ 0x70,
+ 0x71,
+ 0x73,
+ 0x74,
+ 0x75,
+ 0x77,
+ 0x78,
+ 0x7a,
+ 0x7b,
+ 0x7c,
+ 0x7e,
+ 0x7f,
+ 0x80,
+ 0x82,
+ 0x83,
+ 0x84,
+ 0x86,
+ 0x87,
+ 0x88,
+ 0x8a,
+ 0x8b,
+ 0x8c,
+ 0x8e,
+ 0x8f,
+ 0x90,
+ 0x92,
+ 0x93,
+ 0x94,
+ 0x95,
+ 0x97,
+ 0x98,
+ 0x99,
+ 0x9b,
+ 0x9c,
+ 0x9d,
+ 0x9e,
+ 0x9f,
+ 0xa1,
+ 0xa2,
+ 0xa3,
+ 0xa4,
+ 0xa6,
+ 0xa7,
+ 0xa8,
+ 0xa9,
+ 0xaa,
+ 0xab,
+ 0xad,
+ 0xae,
+ 0xaf,
+ 0xb0,
+ 0xb1,
+ 0xb2,
+ 0xb3,
+ 0xb5,
+ 0xb6,
+ 0xb7,
+ 0xb8,
+ 0xb9,
+ 0xba,
+ 0xbb,
+ 0xbc,
+ 0xbd,
+ 0xbe,
+ 0xbf,
+ 0xc0,
+ 0xc1,
+ 0xc2,
+ 0xc3,
+ 0xc4,
+ 0xc5,
+ 0xc6,
+ 0xc7,
+ 0xc8,
+ 0xc9,
+ 0xca,
+ 0xcb,
+ 0xcc,
+ 0xcd,
+ 0xce,
+ 0xcf,
+ 0xd0,
+ 0xd1,
+ 0xd2,
+ 0xd3,
+ 0xd3,
+ 0xd4,
+ 0xd5,
+ 0xd6,
+ 0xd7,
+ 0xd8,
+ 0xd9,
+ 0xd9,
+ 0xda,
+ 0xdb,
+ 0xdc,
+ 0xdd,
+ 0xdd,
+ 0xde,
+ 0xdf,
+ 0xe0,
+ 0xe1,
+ 0xe1,
+ 0xe2,
+ 0xe3,
+ 0xe3,
+ 0xe4,
+ 0xe5,
+ 0xe6,
+ 0xe6,
+ 0xe7,
+ 0xe8,
+ 0xe8,
+ 0xe9,
+ 0xea,
+ 0xea,
+ 0xeb,
+ 0xeb,
+ 0xec,
+ 0xed,
+ 0xed,
+ 0xee,
+ 0xee,
+ 0xef,
+ 0xef,
+ 0xf0,
+ 0xf1,
+ 0xf1,
+ 0xf2,
+ 0xf2,
+ 0xf3,
+ 0xf3,
+ 0xf4,
+ 0xf4,
+ 0xf4,
+ 0xf5,
+ 0xf5,
+ 0xf6,
+ 0xf6,
+ 0xf7,
+ 0xf7,
+ 0xf7,
+ 0xf8,
+ 0xf8,
+ 0xf9,
+ 0xf9,
+ 0xf9,
+ 0xfa,
+ 0xfa,
+ 0xfa,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff
+ };
+
+ // Cosine LUT
+ static private int[] c = {
+ 0x100,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xff,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfe,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfd,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfc,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfb,
+ 0xfa,
+ 0xfa,
+ 0xfa,
+ 0xf9,
+ 0xf9,
+ 0xf9,
+ 0xf8,
+ 0xf8,
+ 0xf7,
+ 0xf7,
+ 0xf7,
+ 0xf6,
+ 0xf6,
+ 0xf5,
+ 0xf5,
+ 0xf4,
+ 0xf4,
+ 0xf4,
+ 0xf3,
+ 0xf3,
+ 0xf2,
+ 0xf2,
+ 0xf1,
+ 0xf1,
+ 0xf0,
+ 0xef,
+ 0xef,
+ 0xee,
+ 0xee,
+ 0xed,
+ 0xed,
+ 0xec,
+ 0xeb,
+ 0xeb,
+ 0xea,
+ 0xea,
+ 0xe9,
+ 0xe8,
+ 0xe8,
+ 0xe7,
+ 0xe6,
+ 0xe6,
+ 0xe5,
+ 0xe4,
+ 0xe3,
+ 0xe3,
+ 0xe2,
+ 0xe1,
+ 0xe1,
+ 0xe0,
+ 0xdf,
+ 0xde,
+ 0xdd,
+ 0xdd,
+ 0xdc,
+ 0xdb,
+ 0xda,
+ 0xd9,
+ 0xd9,
+ 0xd8,
+ 0xd7,
+ 0xd6,
+ 0xd5,
+ 0xd4,
+ 0xd3,
+ 0xd3,
+ 0xd2,
+ 0xd1,
+ 0xd0,
+ 0xcf,
+ 0xce,
+ 0xcd,
+ 0xcc,
+ 0xcb,
+ 0xca,
+ 0xc9,
+ 0xc8,
+ 0xc7,
+ 0xc6,
+ 0xc5,
+ 0xc4,
+ 0xc3,
+ 0xc2,
+ 0xc1,
+ 0xc0,
+ 0xbf,
+ 0xbe,
+ 0xbd,
+ 0xbc,
+ 0xbb,
+ 0xba,
+ 0xb9,
+ 0xb8,
+ 0xb7,
+ 0xb6,
+ 0xb5,
+ 0xb3,
+ 0xb2,
+ 0xb1,
+ 0xb0,
+ 0xaf,
+ 0xae,
+ 0xad,
+ 0xab,
+ 0xaa,
+ 0xa9,
+ 0xa8,
+ 0xa7,
+ 0xa6,
+ 0xa4,
+ 0xa3,
+ 0xa2,
+ 0xa1,
+ 0x9f,
+ 0x9e,
+ 0x9d,
+ 0x9c,
+ 0x9b,
+ 0x99,
+ 0x98,
+ 0x97,
+ 0x95,
+ 0x94,
+ 0x93,
+ 0x92,
+ 0x90,
+ 0x8f,
+ 0x8e,
+ 0x8c,
+ 0x8b,
+ 0x8a,
+ 0x88,
+ 0x87,
+ 0x86,
+ 0x84,
+ 0x83,
+ 0x82,
+ 0x80,
+ 0x7f,
+ 0x7e,
+ 0x7c,
+ 0x7b,
+ 0x7a,
+ 0x78,
+ 0x77,
+ 0x75,
+ 0x74,
+ 0x73,
+ 0x71,
+ 0x70,
+ 0x6e,
+ 0x6d,
+ 0x6c,
+ 0x6a,
+ 0x69,
+ 0x67,
+ 0x66,
+ 0x64,
+ 0x63,
+ 0x61,
+ 0x60,
+ 0x5f,
+ 0x5d,
+ 0x5c,
+ 0x5a,
+ 0x59,
+ 0x57,
+ 0x56,
+ 0x54,
+ 0x53,
+ 0x51,
+ 0x50,
+ 0x4e,
+ 0x4d,
+ 0x4b,
+ 0x4a,
+ 0x48,
+ 0x47,
+ 0x45,
+ 0x44,
+ 0x42,
+ 0x41,
+ 0x3f,
+ 0x3e,
+ 0x3c,
+ 0x3b,
+ 0x39,
+ 0x38,
+ 0x36,
+ 0x35,
+ 0x33,
+ 0x31,
+ 0x30,
+ 0x2e,
+ 0x2d,
+ 0x2b,
+ 0x2a,
+ 0x28,
+ 0x27,
+ 0x25,
+ 0x24,
+ 0x22,
+ 0x20,
+ 0x1f,
+ 0x1d,
+ 0x1c,
+ 0x1a,
+ 0x19,
+ 0x17,
+ 0x15,
+ 0x14,
+ 0x12,
+ 0x11,
+ 0xf,
+ 0xe,
+ 0xc,
+ 0xa,
+ 0x9,
+ 0x7,
+ 0x6,
+ 0x4,
+ 0x3,
+ 0x1
+ };
+
+ /**
+ * Yet to be implemented.
+ * @param num Input
+ * @return Output
+ */
+ public static int arctan( int num ) {
+ return 0;
+ }
+
+ /**
+ * 26.6 fixed number square root function.
+ * Simple (brain-dead) divide & conqure algorithm.
+ * @param num The 26.6 fixed number in question
+ * @return The resulting square root
+ */
+ public static int squareRoot(int num) {
+ int n = num;
+ int divisor = num;
+ int nSquared;
+
+ while (divisor != 0) {
+ divisor /= 2;
+ nSquared = (n * n) >> 6;
+ if (nSquared == num) {
+ break;
+ } else if (nSquared > num) {
+ n -= divisor;
+ } else {
+ n += divisor;
+ }
+ }
+ return n;
+ }
+
+ public static float floatValue(long fixed) {
+ return (fixed >> 16) + (float)(fixed & 0xffff) / 0x10000;
+ }
+
+ public static float roundedFloatValue(long fixed, int decimalPlaces) {
+ int factor = 10 * decimalPlaces;
+ return (float)((int)(floatValue(fixed) * factor)) / factor;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/Mnemonic.java b/src/typecast/net/java/dev/typecast/ot/Mnemonic.java
new file mode 100644
index 000000000..5655c1e86
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/Mnemonic.java
@@ -0,0 +1,397 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot;
+
+/**
+ * The Mnemonic representations of the TrueType instruction set.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Mnemonic.java,v 1.1.1.1 2004-12-05 23:14:30 davidsch Exp $
+ */
+public class Mnemonic {
+
+ public static final short SVTCA = 0x00; // [a]
+ public static final short SPVTCA = 0x02; // [a]
+ public static final short SFVTCA = 0x04; // [a]
+ public static final short SPVTL = 0x06; // [a]
+ public static final short SFVTL = 0x08; // [a]
+ public static final short SPVFS = 0x0A;
+ public static final short SFVFS = 0x0B;
+ public static final short GPV = 0x0C;
+ public static final short GFV = 0x0D;
+ public static final short SFVTPV = 0x0E;
+ public static final short ISECT = 0x0F;
+ public static final short SRP0 = 0x10;
+ public static final short SRP1 = 0x11;
+ public static final short SRP2 = 0x12;
+ public static final short SZP0 = 0x13;
+ public static final short SZP1 = 0x14;
+ public static final short SZP2 = 0x15;
+ public static final short SZPS = 0x16;
+ public static final short SLOOP = 0x17;
+ public static final short RTG = 0x18;
+ public static final short RTHG = 0x19;
+ public static final short SMD = 0x1A;
+ public static final short ELSE = 0x1B;
+ public static final short JMPR = 0x1C;
+ public static final short SCVTCI = 0x1D;
+ public static final short SSWCI = 0x1E;
+ public static final short SSW = 0x1F;
+ public static final short DUP = 0x20;
+ public static final short POP = 0x21;
+ public static final short CLEAR = 0x22;
+ public static final short SWAP = 0x23;
+ public static final short DEPTH = 0x24;
+ public static final short CINDEX = 0x25;
+ public static final short MINDEX = 0x26;
+ public static final short ALIGNPTS = 0x27;
+ public static final short UTP = 0x29;
+ public static final short LOOPCALL = 0x2A;
+ public static final short CALL = 0x2B;
+ public static final short FDEF = 0x2C;
+ public static final short ENDF = 0x2D;
+ public static final short MDAP = 0x2E; // [a]
+ public static final short IUP = 0x30; // [a]
+ public static final short SHP = 0x32;
+ public static final short SHC = 0x34; // [a]
+ public static final short SHZ = 0x36; // [a]
+ public static final short SHPIX = 0x38;
+ public static final short IP = 0x39;
+ public static final short MSIRP = 0x3A; // [a]
+ public static final short ALIGNRP = 0x3C;
+ public static final short RTDG = 0x3D;
+ public static final short MIAP = 0x3E; // [a]
+ public static final short NPUSHB = 0x40;
+ public static final short NPUSHW = 0x41;
+ public static final short WS = 0x42;
+ public static final short RS = 0x43;
+ public static final short WCVTP = 0x44;
+ public static final short RCVT = 0x45;
+ public static final short GC = 0x46; // [a]
+ public static final short SCFS = 0x48;
+ public static final short MD = 0x49; // [a]
+ public static final short MPPEM = 0x4B;
+ public static final short MPS = 0x4C;
+ public static final short FLIPON = 0x4D;
+ public static final short FLIPOFF = 0x4E;
+ public static final short DEBUG = 0x4F;
+ public static final short LT = 0x50;
+ public static final short LTEQ = 0x51;
+ public static final short GT = 0x52;
+ public static final short GTEQ = 0x53;
+ public static final short EQ = 0x54;
+ public static final short NEQ = 0x55;
+ public static final short ODD = 0x56;
+ public static final short EVEN = 0x57;
+ public static final short IF = 0x58;
+ public static final short EIF = 0x59;
+ public static final short AND = 0x5A;
+ public static final short OR = 0x5B;
+ public static final short NOT = 0x5C;
+ public static final short DELTAP1 = 0x5D;
+ public static final short SDB = 0x5E;
+ public static final short SDS = 0x5F;
+ public static final short ADD = 0x60;
+ public static final short SUB = 0x61;
+ public static final short DIV = 0x62;
+ public static final short MUL = 0x63;
+ public static final short ABS = 0x64;
+ public static final short NEG = 0x65;
+ public static final short FLOOR = 0x66;
+ public static final short CEILING = 0x67;
+ public static final short ROUND = 0x68; // [ab]
+ public static final short NROUND = 0x6C; // [ab]
+ public static final short WCVTF = 0x70;
+ public static final short DELTAP2 = 0x71;
+ public static final short DELTAP3 = 0x72;
+ public static final short DELTAC1 = 0x73;
+ public static final short DELTAC2 = 0x74;
+ public static final short DELTAC3 = 0x75;
+ public static final short SROUND = 0x76;
+ public static final short S45ROUND = 0x77;
+ public static final short JROT = 0x78;
+ public static final short JROF = 0x79;
+ public static final short ROFF = 0x7A;
+ public static final short RUTG = 0x7C;
+ public static final short RDTG = 0x7D;
+ public static final short SANGW = 0x7E;
+ public static final short AA = 0x7F;
+ public static final short FLIPPT = 0x80;
+ public static final short FLIPRGON = 0x81;
+ public static final short FLIPRGOFF = 0x82;
+ public static final short SCANCTRL = 0x85;
+ public static final short SDPVTL = 0x86; // [a]
+ public static final short GETINFO = 0x88;
+ public static final short IDEF = 0x89;
+ public static final short ROLL = 0x8A;
+ public static final short MAX = 0x8B;
+ public static final short MIN = 0x8C;
+ public static final short SCANTYPE = 0x8D;
+ public static final short INSTCTRL = 0x8E;
+ public static final short PUSHB = 0xB0; // [abc]
+ public static final short PUSHW = 0xB8; // [abc]
+ public static final short MDRP = 0xC0; // [abcde]
+ public static final short MIRP = 0xE0; // [abcde]
+
+ /**
+ * Gets the mnemonic text for the specified opcode
+ * @param opcode The opcode for which the mnemonic is required
+ * @return The mnemonic, with a description
+ */
+ public static String getMnemonic(short opcode) {
+ if (opcode >= MIRP) return "MIRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]";
+ else if (opcode >= MDRP) return "MDRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]";
+ else if (opcode >= PUSHW) return "PUSHW["+((opcode&7)+1)+"]";
+ else if (opcode >= PUSHB) return "PUSHB["+((opcode&7)+1)+"]";
+ else if (opcode >= INSTCTRL) return "INSTCTRL";
+ else if (opcode >= SCANTYPE) return "SCANTYPE";
+ else if (opcode >= MIN) return "MIN";
+ else if (opcode >= MAX) return "MAX";
+ else if (opcode >= ROLL) return "ROLL";
+ else if (opcode >= IDEF) return "IDEF";
+ else if (opcode >= GETINFO) return "GETINFO";
+ else if (opcode >= SDPVTL) return "SDPVTL["+(opcode&1)+"]";
+ else if (opcode >= SCANCTRL) return "SCANCTRL";
+ else if (opcode >= FLIPRGOFF) return "FLIPRGOFF";
+ else if (opcode >= FLIPRGON) return "FLIPRGON";
+ else if (opcode >= FLIPPT) return "FLIPPT";
+ else if (opcode >= AA) return "AA";
+ else if (opcode >= SANGW) return "SANGW";
+ else if (opcode >= RDTG) return "RDTG";
+ else if (opcode >= RUTG) return "RUTG";
+ else if (opcode >= ROFF) return "ROFF";
+ else if (opcode >= JROF) return "JROF";
+ else if (opcode >= JROT) return "JROT";
+ else if (opcode >= S45ROUND) return "S45ROUND";
+ else if (opcode >= SROUND) return "SROUND";
+ else if (opcode >= DELTAC3) return "DELTAC3";
+ else if (opcode >= DELTAC2) return "DELTAC2";
+ else if (opcode >= DELTAC1) return "DELTAC1";
+ else if (opcode >= DELTAP3) return "DELTAP3";
+ else if (opcode >= DELTAP2) return "DELTAP2";
+ else if (opcode >= WCVTF) return "WCVTF";
+ else if (opcode >= NROUND) return "NROUND["+(opcode&3)+"]";
+ else if (opcode >= ROUND) return "ROUND["+(opcode&3)+"]";
+ else if (opcode >= CEILING) return "CEILING";
+ else if (opcode >= FLOOR) return "FLOOR";
+ else if (opcode >= NEG) return "NEG";
+ else if (opcode >= ABS) return "ABS";
+ else if (opcode >= MUL) return "MUL";
+ else if (opcode >= DIV) return "DIV";
+ else if (opcode >= SUB) return "SUB";
+ else if (opcode >= ADD) return "ADD";
+ else if (opcode >= SDS) return "SDS";
+ else if (opcode >= SDB) return "SDB";
+ else if (opcode >= DELTAP1) return "DELTAP1";
+ else if (opcode >= NOT) return "NOT";
+ else if (opcode >= OR) return "OR";
+ else if (opcode >= AND) return "AND";
+ else if (opcode >= EIF) return "EIF";
+ else if (opcode >= IF) return "IF";
+ else if (opcode >= EVEN) return "EVEN";
+ else if (opcode >= ODD) return "ODD";
+ else if (opcode >= NEQ) return "NEQ";
+ else if (opcode >= EQ) return "EQ";
+ else if (opcode >= GTEQ) return "GTEQ";
+ else if (opcode >= GT) return "GT";
+ else if (opcode >= LTEQ) return "LTEQ";
+ else if (opcode >= LT) return "LT";
+ else if (opcode >= DEBUG) return "DEBUG";
+ else if (opcode >= FLIPOFF) return "FLIPOFF";
+ else if (opcode >= FLIPON) return "FLIPON";
+ else if (opcode >= MPS) return "MPS";
+ else if (opcode >= MPPEM) return "MPPEM";
+ else if (opcode >= MD) return "MD["+(opcode&1)+"]";
+ else if (opcode >= SCFS) return "SCFS";
+ else if (opcode >= GC) return "GC["+(opcode&1)+"]";
+ else if (opcode >= RCVT) return "RCVT";
+ else if (opcode >= WCVTP) return "WCVTP";
+ else if (opcode >= RS) return "RS";
+ else if (opcode >= WS) return "WS";
+ else if (opcode >= NPUSHW) return "NPUSHW";
+ else if (opcode >= NPUSHB) return "NPUSHB";
+ else if (opcode >= MIAP) return "MIAP["+((opcode&1)==0?"nrd+nci":"rd+ci")+"]";
+ else if (opcode >= RTDG) return "RTDG";
+ else if (opcode >= ALIGNRP) return "ALIGNRP";
+ else if (opcode >= MSIRP) return "MSIRP["+(opcode&1)+"]";
+ else if (opcode >= IP) return "IP";
+ else if (opcode >= SHPIX) return "SHPIX";
+ else if (opcode >= SHZ) return "SHZ["+(opcode&1)+"]";
+ else if (opcode >= SHC) return "SHC["+(opcode&1)+"]";
+ else if (opcode >= SHP) return "SHP";
+ else if (opcode >= IUP) return "IUP["+((opcode&1)==0?"y":"x")+"]";
+ else if (opcode >= MDAP) return "MDAP["+((opcode&1)==0?"nrd":"rd")+"]";
+ else if (opcode >= ENDF) return "ENDF";
+ else if (opcode >= FDEF) return "FDEF";
+ else if (opcode >= CALL) return "CALL";
+ else if (opcode >= LOOPCALL) return "LOOPCALL";
+ else if (opcode >= UTP) return "UTP";
+ else if (opcode >= ALIGNPTS) return "ALIGNPTS";
+ else if (opcode >= MINDEX) return "MINDEX";
+ else if (opcode >= CINDEX) return "CINDEX";
+ else if (opcode >= DEPTH) return "DEPTH";
+ else if (opcode >= SWAP) return "SWAP";
+ else if (opcode >= CLEAR) return "CLEAR";
+ else if (opcode >= POP) return "POP";
+ else if (opcode >= DUP) return "DUP";
+ else if (opcode >= SSW) return "SSW";
+ else if (opcode >= SSWCI) return "SSWCI";
+ else if (opcode >= SCVTCI) return "SCVTCI";
+ else if (opcode >= JMPR) return "JMPR";
+ else if (opcode >= ELSE) return "ELSE";
+ else if (opcode >= SMD) return "SMD";
+ else if (opcode >= RTHG) return "RTHG";
+ else if (opcode >= RTG) return "RTG";
+ else if (opcode >= SLOOP) return "SLOOP";
+ else if (opcode >= SZPS) return "SZPS";
+ else if (opcode >= SZP2) return "SZP2";
+ else if (opcode >= SZP1) return "SZP1";
+ else if (opcode >= SZP0) return "SZP0";
+ else if (opcode >= SRP2) return "SRP2";
+ else if (opcode >= SRP1) return "SRP1";
+ else if (opcode >= SRP0) return "SRP0";
+ else if (opcode >= ISECT) return "ISECT";
+ else if (opcode >= SFVTPV) return "SFVTPV";
+ else if (opcode >= GFV) return "GFV";
+ else if (opcode >= GPV) return "GPV";
+ else if (opcode >= SFVFS) return "SFVFS";
+ else if (opcode >= SPVFS) return "SPVFS";
+ else if (opcode >= SFVTL) return "SFVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SPVTL) return "SPVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SFVTCA) return "SFVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SPVTCA) return "SPVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else if (opcode >= SVTCA) return "SVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]";
+ else return "????";
+ }
+
+ public static String getComment(short opcode) {
+ if (opcode >= MIRP) return "MIRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]\t\tMove Indirect Relative Point";
+ else if (opcode >= MDRP) return "MDRP["+((opcode&16)==0?"nrp0,":"srp0,")+((opcode&8)==0?"nmd,":"md,")+((opcode&4)==0?"nrd,":"rd,")+(opcode&3)+"]\t\tMove Direct Relative Point";
+ else if (opcode >= PUSHW) return "PUSHW["+((opcode&7)+1)+"]";
+ else if (opcode >= PUSHB) return "PUSHB["+((opcode&7)+1)+"]";
+ else if (opcode >= INSTCTRL) return "INSTCTRL\tINSTruction Execution ConTRol";
+ else if (opcode >= SCANTYPE) return "SCANTYPE\tSCANTYPE";
+ else if (opcode >= MIN) return "MIN\t\tMINimum of top two stack elements";
+ else if (opcode >= MAX) return "MAX\t\tMAXimum of top two stack elements";
+ else if (opcode >= ROLL) return "ROLL\t\tROLL the top three stack elements";
+ else if (opcode >= IDEF) return "IDEF\t\tInstruction DEFinition";
+ else if (opcode >= GETINFO) return "GETINFO\tGET INFOrmation";
+ else if (opcode >= SDPVTL) return "SDPVTL["+(opcode&1)+"]\tSet Dual Projection_Vector To Line";
+ else if (opcode >= SCANCTRL) return "SCANCTRL\tSCAN conversion ConTRoL";
+ else if (opcode >= FLIPRGOFF) return "FLIPRGOFF\tFLIP RanGe OFF";
+ else if (opcode >= FLIPRGON) return "FLIPRGON\tFLIP RanGe ON";
+ else if (opcode >= FLIPPT) return "FLIPPT\tFLIP PoinT";
+ else if (opcode >= AA) return "AA";
+ else if (opcode >= SANGW) return "SANGW\t\tSet Angle _Weight";
+ else if (opcode >= RDTG) return "RDTG\t\tRound Down To Grid";
+ else if (opcode >= RUTG) return "RUTG\t\tRound Up To Grid";
+ else if (opcode >= ROFF) return "ROFF\t\tRound OFF";
+ else if (opcode >= JROF) return "JROF\t\tJump Relative On False";
+ else if (opcode >= JROT) return "JROT\t\tJump Relative On True";
+ else if (opcode >= S45ROUND) return "S45ROUND\tSuper ROUND 45 degrees";
+ else if (opcode >= SROUND) return "SROUND\tSuper ROUND";
+ else if (opcode >= DELTAC3) return "DELTAC3\tDELTA exception C3";
+ else if (opcode >= DELTAC2) return "DELTAC2\tDELTA exception C2";
+ else if (opcode >= DELTAC1) return "DELTAC1\tDELTA exception C1";
+ else if (opcode >= DELTAP3) return "DELTAP3\tDELTA exception P3";
+ else if (opcode >= DELTAP2) return "DELTAP2\tDELTA exception P2";
+ else if (opcode >= WCVTF) return "WCVTF\t\tWrite Control Value Table in FUnits";
+ else if (opcode >= NROUND) return "NROUND["+(opcode&3)+"]";
+ else if (opcode >= ROUND) return "ROUND["+(opcode&3)+"]";
+ else if (opcode >= CEILING) return "CEILING\tCEILING";
+ else if (opcode >= FLOOR) return "FLOOR\t\tFLOOR";
+ else if (opcode >= NEG) return "NEG\t\tNEGate";
+ else if (opcode >= ABS) return "ABS\t\tABSolute value";
+ else if (opcode >= MUL) return "MUL\t\tMULtiply";
+ else if (opcode >= DIV) return "DIV\t\tDIVide";
+ else if (opcode >= SUB) return "SUB\t\tSUBtract";
+ else if (opcode >= ADD) return "ADD\t\tADD";
+ else if (opcode >= SDS) return "SDS\t\tSet Delta_Shift in the graphics state";
+ else if (opcode >= SDB) return "SDB\t\tSet Delta_Base in the graphics state";
+ else if (opcode >= DELTAP1) return "DELTAP1\tDELTA exception P1";
+ else if (opcode >= NOT) return "NOT\t\tlogical NOT";
+ else if (opcode >= OR) return "OR\t\t\tlogical OR";
+ else if (opcode >= AND) return "AND\t\tlogical AND";
+ else if (opcode >= EIF) return "EIF\t\tEnd IF";
+ else if (opcode >= IF) return "IF\t\t\tIF test";
+ else if (opcode >= EVEN) return "EVEN";
+ else if (opcode >= ODD) return "ODD";
+ else if (opcode >= NEQ) return "NEQ\t\tNot EQual";
+ else if (opcode >= EQ) return "EQ\t\t\tEQual";
+ else if (opcode >= GTEQ) return "GTEQ\t\tGreater Than or Equal";
+ else if (opcode >= GT) return "GT\t\t\tGreater Than";
+ else if (opcode >= LTEQ) return "LTEQ\t\tLess Than or Equal";
+ else if (opcode >= LT) return "LT\t\t\tLess Than";
+ else if (opcode >= DEBUG) return "DEBUG";
+ else if (opcode >= FLIPOFF) return "FLIPOFF\tSet the auto_flip Boolean to OFF";
+ else if (opcode >= FLIPON) return "FLIPON\tSet the auto_flip Boolean to ON";
+ else if (opcode >= MPS) return "MPS\t\tMeasure Point Size";
+ else if (opcode >= MPPEM) return "MPPEM\t\tMeasure Pixels Per EM";
+ else if (opcode >= MD) return "MD["+(opcode&1)+"]\t\t\tMeasure Distance";
+ else if (opcode >= SCFS) return "SCFS\t\tSets Coordinate From the Stack using projection_vector and freedom_vector";
+ else if (opcode >= GC) return "GC["+(opcode&1)+"]\t\t\tGet Coordinate projected onto the projection_vector";
+ else if (opcode >= RCVT) return "RCVT\t\tRead Control Value Table";
+ else if (opcode >= WCVTP) return "WCVTP\t\tWrite Control Value Table in Pixel units";
+ else if (opcode >= RS) return "RS\t\t\tRead Store";
+ else if (opcode >= WS) return "WS\t\t\tWrite Store";
+ else if (opcode >= NPUSHW) return "NPUSHW";
+ else if (opcode >= NPUSHB) return "NPUSHB";
+ else if (opcode >= MIAP) return "MIAP["+((opcode&1)==0?"nrd+nci":"rd+ci")+"]\t\tMove Indirect Absolute Point";
+ else if (opcode >= RTDG) return "RTDG\t\tRound To Double Grid";
+ else if (opcode >= ALIGNRP) return "ALIGNRP\tALIGN Relative Point";
+ else if (opcode >= MSIRP) return "MSIRP["+(opcode&1)+"]\t\tMove Stack Indirect Relative Point";
+ else if (opcode >= IP) return "IP\t\t\tInterpolate Point by the last relative stretch";
+ else if (opcode >= SHPIX) return "SHPIX\t\tSHift point by a PIXel amount";
+ else if (opcode >= SHZ) return "SHZ["+(opcode&1)+"]\t\tSHift Zone by the last pt";
+ else if (opcode >= SHC) return "SHC["+(opcode&1)+"]\t\tSHift Contour by the last point";
+ else if (opcode >= SHP) return "SHP\t\tSHift Point by the last point";
+ else if (opcode >= IUP) return "IUP["+((opcode&1)==0?"y":"x")+"]\t\tInterpolate Untouched Points through the outline";
+ else if (opcode >= MDAP) return "MDAP["+((opcode&1)==0?"nrd":"rd")+"]\t\tMove Direct Absolute Point";
+ else if (opcode >= ENDF) return "ENDF\t\tEND Function definition";
+ else if (opcode >= FDEF) return "FDEF\t\tFunction DEFinition ";
+ else if (opcode >= CALL) return "CALL\t\tCALL function";
+ else if (opcode >= LOOPCALL) return "LOOPCALL\tLOOP and CALL function";
+ else if (opcode >= UTP) return "UTP\t\tUnTouch Point";
+ else if (opcode >= ALIGNPTS) return "ALIGNPTS\tALIGN Points";
+ else if (opcode >= MINDEX) return "MINDEX\tMove the INDEXed element to the top of the stack";
+ else if (opcode >= CINDEX) return "CINDEX\tCopy the INDEXed element to the top of the stack";
+ else if (opcode >= DEPTH) return "DEPTH\t\tReturns the DEPTH of the stack";
+ else if (opcode >= SWAP) return "SWAP\t\tSWAP the top two elements on the stack";
+ else if (opcode >= CLEAR) return "CLEAR\t\tClear the entire stack";
+ else if (opcode >= POP) return "POP\t\tPOP top stack element";
+ else if (opcode >= DUP) return "DUP\t\tDuplicate top stack element";
+ else if (opcode >= SSW) return "SSW\t\tSet Single-width";
+ else if (opcode >= SSWCI) return "SSWCI\t\tSet Single_Width_Cut_In";
+ else if (opcode >= SCVTCI) return "SCVTCI\tSet Control Value Table Cut In";
+ else if (opcode >= JMPR) return "JMPR\t\tJuMP";
+ else if (opcode >= ELSE) return "ELSE";
+ else if (opcode >= SMD) return "SMD\t\tSet Minimum_ Distance";
+ else if (opcode >= RTHG) return "RTHG\t\tRound To Half Grid";
+ else if (opcode >= RTG) return "RTG\t\tRound To Grid";
+ else if (opcode >= SLOOP) return "SLOOP\t\tSet LOOP variable";
+ else if (opcode >= SZPS) return "SZPS\t\tSet Zone PointerS";
+ else if (opcode >= SZP2) return "SZP2\t\tSet Zone Pointer 2";
+ else if (opcode >= SZP1) return "SZP1\t\tSet Zone Pointer 1";
+ else if (opcode >= SZP0) return "SZP0\t\tSet Zone Pointer 0";
+ else if (opcode >= SRP2) return "SRP2\t\tSet Reference Point 2";
+ else if (opcode >= SRP1) return "SRP1\t\tSet Reference Point 1";
+ else if (opcode >= SRP0) return "SRP0\t\tSet Reference Point 0";
+ else if (opcode >= ISECT) return "ISECT\t\tmoves point p to the InterSECTion of two lines";
+ else if (opcode >= SFVTPV) return "SFVTPV\tSet Freedom_Vector To Projection Vector";
+ else if (opcode >= GFV) return "GFV\t\tGet Freedom_Vector";
+ else if (opcode >= GPV) return "GPV\t\tGet Projection_Vector";
+ else if (opcode >= SFVFS) return "SFVFS\t\tSet Freedom_Vector From Stack";
+ else if (opcode >= SPVFS) return "SPVFS\t\tSet Projection_Vector From Stack";
+ else if (opcode >= SFVTL) return "SFVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]\t\tSet Freedom_Vector To Line";
+ else if (opcode >= SPVTL) return "SPVTL["+((opcode&1)==0?"y-axis":"x-axis")+"]\t\tSet Projection_Vector To Line";
+ else if (opcode >= SFVTCA) return "SFVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]\tSet Freedom_Vector to Coordinate Axis";
+ else if (opcode >= SPVTCA) return "SPVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]\tSet Projection_Vector To Coordinate Axis";
+ else if (opcode >= SVTCA) return "SVTCA["+((opcode&1)==0?"y-axis":"x-axis")+"]\t\tSet freedom and projection Vectors To Coordinate Axis";
+ else return "????";
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/OTFont.java b/src/typecast/net/java/dev/typecast/ot/OTFont.java
new file mode 100644
index 000000000..e58fc3794
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/OTFont.java
@@ -0,0 +1,274 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import net.java.dev.typecast.ot.table.DirectoryEntry;
+import net.java.dev.typecast.ot.table.GlyfDescript;
+import net.java.dev.typecast.ot.table.HdmxTable;
+import net.java.dev.typecast.ot.table.TableDirectory;
+import net.java.dev.typecast.ot.table.Table;
+import net.java.dev.typecast.ot.table.Os2Table;
+import net.java.dev.typecast.ot.table.CmapTable;
+import net.java.dev.typecast.ot.table.GlyfTable;
+import net.java.dev.typecast.ot.table.HeadTable;
+import net.java.dev.typecast.ot.table.HheaTable;
+import net.java.dev.typecast.ot.table.HmtxTable;
+import net.java.dev.typecast.ot.table.LocaTable;
+import net.java.dev.typecast.ot.table.MaxpTable;
+import net.java.dev.typecast.ot.table.NameTable;
+import net.java.dev.typecast.ot.table.PostTable;
+import net.java.dev.typecast.ot.table.VheaTable;
+import net.java.dev.typecast.ot.table.TableFactory;
+
+/**
+ * The TrueType font.
+ * @version $Id: OTFont.java,v 1.6 2007-01-31 01:49:18 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>, Sven Gothel
+ */
+public class OTFont {
+
+ private OTFontCollection _fc;
+ private TableDirectory _tableDirectory = null;
+ private Table[] _tables;
+ private Os2Table _os2;
+ private CmapTable _cmap;
+ private GlyfTable _glyf;
+ private HeadTable _head;
+ private HheaTable _hhea;
+ private HdmxTable _hdmx;
+ private HmtxTable _hmtx;
+ private LocaTable _loca;
+ private MaxpTable _maxp;
+ private NameTable _name;
+ private PostTable _post;
+ private VheaTable _vhea;
+
+ /**
+ * Constructor
+ */
+ public OTFont(OTFontCollection fc) {
+ _fc = fc;
+ }
+
+ public Table getTable(int tableType) {
+ for (int i = 0; i < _tables.length; i++) {
+ if ((_tables[i] != null) && (_tables[i].getType() == tableType)) {
+ return _tables[i];
+ }
+ }
+ return null;
+ }
+
+ public Os2Table getOS2Table() {
+ return _os2;
+ }
+
+ public CmapTable getCmapTable() {
+ return _cmap;
+ }
+
+ public HeadTable getHeadTable() {
+ return _head;
+ }
+
+ public HheaTable getHheaTable() {
+ return _hhea;
+ }
+
+ public HdmxTable getHdmxTable() {
+ return _hdmx;
+ }
+
+ public HmtxTable getHmtxTable() {
+ return _hmtx;
+ }
+
+ public LocaTable getLocaTable() {
+ return _loca;
+ }
+
+ public MaxpTable getMaxpTable() {
+ return _maxp;
+ }
+
+ public NameTable getNameTable() {
+ return _name;
+ }
+
+ public PostTable getPostTable() {
+ return _post;
+ }
+
+ public VheaTable getVheaTable() {
+ return _vhea;
+ }
+
+ public int getAscent() {
+ return _hhea.getAscender();
+ }
+
+ public int getDescent() {
+ return _hhea.getDescender();
+ }
+
+ public int getNumGlyphs() {
+ return _maxp.getNumGlyphs();
+ }
+
+ public OTGlyph getGlyph(int i) {
+
+ final GlyfDescript _glyfDescr = _glyf.getDescription(i);
+ return (null != _glyfDescr)
+ ? new OTGlyph(
+ _glyfDescr,
+ _hmtx.getLeftSideBearing(i),
+ _hmtx.getAdvanceWidth(i))
+ : null;
+ }
+
+ public TableDirectory getTableDirectory() {
+ return _tableDirectory;
+ }
+
+ private Table readTable(
+ DataInputStream dis,
+ int tablesOrigin,
+ int tag) throws IOException {
+ dis.reset();
+ DirectoryEntry entry = _tableDirectory.getEntryByTag(tag);
+ if (entry == null) {
+ return null;
+ }
+ dis.skip(tablesOrigin + entry.getOffset());
+ return TableFactory.create(_fc, this, entry, dis);
+ }
+
+ /**
+ * @param dis OpenType/TrueType font file data.
+ * @param directoryOffset The Table Directory offset within the file. For a
+ * regular TTF/OTF file this will be zero, but for a TTC (Font Collection)
+ * the offset is retrieved from the TTC header. For a Mac font resource,
+ * offset is retrieved from the resource headers.
+ * @param tablesOrigin The point the table offsets are calculated from.
+ * Once again, in a regular TTF file, this will be zero. In a TTC is is
+ * also zero, but within a Mac resource, it is the beggining of the
+ * individual font resource data.
+ */
+ protected void read(
+ DataInputStream dis,
+ int directoryOffset,
+ int tablesOrigin) throws IOException {
+
+ // Load the table directory
+ dis.reset();
+ dis.skip(directoryOffset);
+ _tableDirectory = new TableDirectory(dis);
+ _tables = new Table[_tableDirectory.getNumTables()];
+
+ // Load some prerequisite tables
+ _head = (HeadTable) readTable(dis, tablesOrigin, Table.head);
+ _hhea = (HheaTable) readTable(dis, tablesOrigin, Table.hhea);
+ _maxp = (MaxpTable) readTable(dis, tablesOrigin, Table.maxp);
+ _loca = (LocaTable) readTable(dis, tablesOrigin, Table.loca);
+ _vhea = (VheaTable) readTable(dis, tablesOrigin, Table.vhea);
+
+ int index = 0;
+ _tables[index++] = _head;
+ _tables[index++] = _hhea;
+ _tables[index++] = _maxp;
+ if (_loca != null) {
+ _tables[index++] = _loca;
+ }
+ if (_vhea != null) {
+ _tables[index++] = _vhea;
+ }
+
+ // Load all other tables
+ for (int i = 0; i < _tableDirectory.getNumTables(); i++) {
+ DirectoryEntry entry = _tableDirectory.getEntry(i);
+ if (entry.getTag() == Table.head
+ || entry.getTag() == Table.hhea
+ || entry.getTag() == Table.maxp
+ || entry.getTag() == Table.loca
+ || entry.getTag() == Table.vhea) {
+ continue;
+ }
+ dis.reset();
+ dis.skip(tablesOrigin + entry.getOffset());
+ _tables[index] = TableFactory.create(_fc, this, entry, dis);
+ ++index;
+ }
+
+ // Get references to commonly used tables (these happen to be all the
+ // required tables)
+ _cmap = (CmapTable) getTable(Table.cmap);
+ _hdmx = (HdmxTable) getTable(Table.hdmx);
+ _hmtx = (HmtxTable) getTable(Table.hmtx);
+ _name = (NameTable) getTable(Table.name);
+ _os2 = (Os2Table) getTable(Table.OS_2);
+ _post = (PostTable) getTable(Table.post);
+
+ // If this is a TrueType outline, then we'll have at least the
+ // 'glyf' table (along with the 'loca' table)
+ _glyf = (GlyfTable) getTable(Table.glyf);
+ }
+
+ public String toString() {
+ if (_tableDirectory != null) {
+ return _tableDirectory.toString();
+ } else {
+ return "Empty font";
+ }
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/OTFontCollection.java b/src/typecast/net/java/dev/typecast/ot/OTFontCollection.java
new file mode 100644
index 000000000..6f8754f59
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/OTFontCollection.java
@@ -0,0 +1,169 @@
+/*
+ * $Id: OTFontCollection.java,v 1.6 2010-08-10 11:38:11 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot;
+
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+
+import net.java.dev.typecast.ot.mac.ResourceHeader;
+import net.java.dev.typecast.ot.mac.ResourceMap;
+import net.java.dev.typecast.ot.mac.ResourceReference;
+import net.java.dev.typecast.ot.mac.ResourceType;
+import net.java.dev.typecast.ot.table.DirectoryEntry;
+import net.java.dev.typecast.ot.table.Table;
+import net.java.dev.typecast.ot.table.TTCHeader;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: OTFontCollection.java,v 1.6 2010-08-10 11:38:11 davidsch Exp $
+ */
+public class OTFontCollection {
+
+ private String _pathName;
+ private String _fileName;
+ private TTCHeader _ttcHeader;
+ private OTFont[] _fonts;
+ private ArrayList<Table> _tables = new ArrayList<Table>();
+ private boolean _resourceFork = false;
+
+ /** Creates new FontCollection */
+ protected OTFontCollection() {
+ }
+
+ /**
+ * @param file The OpenType font file
+ */
+ public static OTFontCollection create(File file) throws IOException {
+ OTFontCollection fc = new OTFontCollection();
+ fc.read(file);
+ return fc;
+ }
+
+ public String getPathName() {
+ return _pathName;
+ }
+
+ public String getFileName() {
+ return _fileName;
+ }
+
+ public OTFont getFont(int i) {
+ return _fonts[i];
+ }
+
+ public int getFontCount() {
+ return _fonts.length;
+ }
+
+ public TTCHeader getTtcHeader() {
+ return _ttcHeader;
+ }
+
+ public Table getTable(DirectoryEntry de) {
+ for (int i = 0; i < _tables.size(); i++) {
+ Table table = _tables.get(i);
+ if ((table.getDirectoryEntry().getTag() == de.getTag()) &&
+ (table.getDirectoryEntry().getOffset() == de.getOffset())) {
+ return table;
+ }
+ }
+ return null;
+ }
+
+ public void addTable(Table table) {
+ _tables.add(table);
+ }
+
+ /**
+ * @param file The OpenType font file
+ */
+ protected void read(File file) throws IOException {
+ _pathName = file.getPath();
+ _fileName = file.getName();
+
+ if (!file.exists()) {
+ throw new IOException();
+ }
+
+ // Do we need to modify the path name to deal with font resources
+ // in a Mac resource fork?
+ if (file.length() == 0) {
+ file = new File(file, "..namedfork/rsrc");
+ if (!file.exists()) {
+ throw new IOException();
+ }
+ _resourceFork = true;
+ }
+
+ DataInputStream dis = new DataInputStream(
+ new BufferedInputStream(
+ new FileInputStream(file), (int) file.length()));
+ dis.mark((int) file.length());
+
+ if (_resourceFork || _pathName.endsWith(".dfont")) {
+
+ // This is a Macintosh font suitcase resource
+ ResourceHeader resourceHeader = new ResourceHeader(dis);
+
+ // Seek to the map offset and read the map
+ dis.reset();
+ dis.skip(resourceHeader.getMapOffset());
+ ResourceMap map = new ResourceMap(dis);
+
+ // Get the 'sfnt' resources
+ ResourceType resourceType = map.getResourceType("sfnt");
+
+ // Load the font data
+ _fonts = new OTFont[resourceType.getCount()];
+ for (int i = 0; i < resourceType.getCount(); i++) {
+ ResourceReference resourceReference = resourceType.getReference(i);
+ _fonts[i] = new OTFont(this);
+ int offset = resourceHeader.getDataOffset() +
+ resourceReference.getDataOffset() + 4;
+ _fonts[i].read(dis, offset, offset);
+ }
+
+ } else if (TTCHeader.isTTC(dis)) {
+
+ // This is a TrueType font collection
+ dis.reset();
+ _ttcHeader = new TTCHeader(dis);
+ _fonts = new OTFont[_ttcHeader.getDirectoryCount()];
+ for (int i = 0; i < _ttcHeader.getDirectoryCount(); i++) {
+ _fonts[i] = new OTFont(this);
+ _fonts[i].read(dis, _ttcHeader.getTableDirectory(i), 0);
+ }
+ } else {
+
+ // This is a standalone font file
+ _fonts = new OTFont[1];
+ _fonts[0] = new OTFont(this);
+ _fonts[0].read(dis, 0, 0);
+ }
+ dis.close();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/OTGlyph.java b/src/typecast/net/java/dev/typecast/ot/OTGlyph.java
new file mode 100644
index 000000000..958dd2280
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/OTGlyph.java
@@ -0,0 +1,168 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot;
+
+import com.jogamp.graph.geom.AABBox;
+
+import net.java.dev.typecast.ot.table.GlyphDescription;
+import net.java.dev.typecast.ot.table.GlyfDescript;
+import net.java.dev.typecast.ot.table.Charstring;
+import net.java.dev.typecast.ot.table.CharstringType2;
+
+import net.java.dev.typecast.t2.T2Interpreter;
+
+/**
+ * An individual glyph within a font.
+ * @version $Id: Glyph.java,v 1.3 2007-02-21 12:23:54 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>, Sven Gothel
+ */
+public class OTGlyph {
+
+ protected short _leftSideBearing;
+ protected int _advanceWidth;
+ private Point[] _points;
+ AABBox _bbox;
+
+ /**
+ * Construct a Glyph from a TrueType outline described by
+ * a GlyphDescription.
+ * @param cs The Charstring describing the glyph.
+ * @param lsb The Left Side Bearing.
+ * @param advance The advance width.
+ */
+ public OTGlyph(GlyphDescription gd, short lsb, int advance) {
+ _leftSideBearing = lsb;
+ _advanceWidth = advance;
+ describe(gd);
+ }
+
+ /**
+ * Construct a Glyph from a PostScript outline described by a Charstring.
+ * @param cs The Charstring describing the glyph.
+ * @param lsb The Left Side Bearing.
+ * @param advance The advance width.
+ */
+ public OTGlyph(Charstring cs, short lsb, int advance) {
+ _leftSideBearing = lsb;
+ _advanceWidth = advance;
+ if (cs instanceof CharstringType2) {
+ T2Interpreter t2i = new T2Interpreter();
+ _points = t2i.execute((CharstringType2) cs);
+ } else {
+ //throw unsupported charstring type
+ }
+ }
+
+ public AABBox getBBox() {
+ return _bbox;
+ }
+
+ public int getAdvanceWidth() {
+ return _advanceWidth;
+ }
+
+ public short getLeftSideBearing() {
+ return _leftSideBearing;
+ }
+
+ public Point getPoint(int i) {
+ return _points[i];
+ }
+
+ public int getPointCount() {
+ return _points.length;
+ }
+
+ /**
+ * Resets the glyph to the TrueType table settings
+ */
+ public void reset() {
+ }
+
+ /**
+ * @param factor a 16.16 fixed value
+ */
+ public void scale(int factor) {
+ for (int i = 0; i < _points.length; i++) {
+ //points[i].x = ( points[i].x * factor ) >> 6;
+ //points[i].y = ( points[i].y * factor ) >> 6;
+ _points[i].x = ((_points[i].x<<10) * factor) >> 26;
+ _points[i].y = ((_points[i].y<<10) * factor) >> 26;
+ }
+ _leftSideBearing = (short)(( _leftSideBearing * factor) >> 6);
+ _advanceWidth = (_advanceWidth * factor) >> 6;
+ }
+
+ /**
+ * Set the points of a glyph from the GlyphDescription
+ */
+ private void describe(GlyphDescription gd) {
+ int endPtIndex = 0;
+ _points = new Point[gd.getPointCount() /* + 2 */ ];
+ for (int i = 0; i < gd.getPointCount(); i++) {
+ boolean endPt = gd.getEndPtOfContours(endPtIndex) == i;
+ if (endPt) {
+ endPtIndex++;
+ }
+ _points[i] = new Point(
+ gd.getXCoordinate(i),
+ gd.getYCoordinate(i),
+ (gd.getFlags(i) & GlyfDescript.onCurve) != 0,
+ endPt);
+ }
+
+ // Append the origin and advanceWidth points (n & n+1)
+ // _points[gd.getPointCount()] = new Point(0, 0, true, true);
+ // _points[gd.getPointCount()+1] = new Point(_advanceWidth, 0, true, true);
+
+ _bbox = new AABBox(gd.getXMinimum(), gd.getYMinimum(), 0, gd.getXMaximum(), gd.getYMaximum(), 0);
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/Point.java b/src/typecast/net/java/dev/typecast/ot/Point.java
new file mode 100644
index 000000000..fae13b098
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/Point.java
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot;
+
+/**
+ * @version $Id: Point.java,v 1.1.1.1 2004-12-05 23:14:31 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class Point {
+
+ public int x = 0;
+ 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;
+ this.y = y;
+ this.onCurve = onCurve;
+ this.endOfContour = endOfContour;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/mac/ResourceData.java b/src/typecast/net/java/dev/typecast/ot/mac/ResourceData.java
new file mode 100644
index 000000000..a1c12ffc0
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/mac/ResourceData.java
@@ -0,0 +1,45 @@
+/*
+ * $Id: ResourceData.java,v 1.1.1.1 2004-12-05 23:14:31 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceData.java,v 1.1.1.1 2004-12-05 23:14:31 davidsch Exp $
+ */
+public class ResourceData {
+
+ private byte[] data;
+
+ /** Creates new ResourceData */
+ public ResourceData(DataInput di) throws IOException {
+ int dataLen = di.readInt();
+ data = new byte[dataLen];
+ di.readFully(data);
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/mac/ResourceFile.java b/src/typecast/net/java/dev/typecast/ot/mac/ResourceFile.java
new file mode 100644
index 000000000..e9499d9e8
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/mac/ResourceFile.java
@@ -0,0 +1,77 @@
+/*
+ * $Id: ResourceFile.java,v 1.2 2007-01-29 04:01:53 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Mac resource loading test.
+ * TODO: incorporate this into the test suite.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceFile.java,v 1.2 2007-01-29 04:01:53 davidsch Exp $
+ */
+public class ResourceFile {
+
+ private ResourceHeader header;
+ private ResourceMap map;
+
+ /** Creates new Resource */
+ public ResourceFile(RandomAccessFile raf) throws IOException {
+
+ // Read header at the beginning of the file
+ raf.seek(0);
+ header = new ResourceHeader(raf);
+
+ // Seek to the map offset and read the map
+ raf.seek(header.getMapOffset());
+ map = new ResourceMap(raf);
+ }
+
+ public ResourceMap getResourceMap() {
+ return map;
+ }
+
+ public static void main(String[] args) {
+ try {
+ //RandomAccessFile raf = new RandomAccessFile("/Library/Fonts/GillSans.dfont", "r");
+
+ // Tests loading a font from a resource fork on Mac OS X
+ RandomAccessFile raf = new RandomAccessFile("/Library/Fonts/Georgia/..namedfork/rsrc", "r");
+ ResourceFile resource = new ResourceFile(raf);
+ for (int i = 0; i < resource.getResourceMap().getResourceTypeCount(); i++) {
+ System.out.println(resource.getResourceMap().getResourceType(i).getTypeAsString());
+ }
+
+ // Get the first 'sfnt' resource
+ ResourceType type = resource.getResourceMap().getResourceType("sfnt");
+ ResourceReference reference = type.getReference(0);
+
+ type = resource.getResourceMap().getResourceType("FOND");
+ for (int i = 0; i < type.getCount(); ++i) {
+ reference = type.getReference(i);
+ System.out.println(reference.getName());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/mac/ResourceHeader.java b/src/typecast/net/java/dev/typecast/ot/mac/ResourceHeader.java
new file mode 100644
index 000000000..bdfe15a72
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/mac/ResourceHeader.java
@@ -0,0 +1,61 @@
+/*
+ * $Id: ResourceHeader.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceHeader.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ */
+public class ResourceHeader {
+
+ private int dataOffset;
+ private int mapOffset;
+ private int dataLen;
+ private int mapLen;
+
+ /** Creates new ResourceHeader */
+ public ResourceHeader(DataInput di) throws IOException {
+ dataOffset = di.readInt();
+ mapOffset = di.readInt();
+ dataLen = di.readInt();
+ mapLen = di.readInt();
+ }
+
+ public int getDataOffset() {
+ return dataOffset;
+ }
+
+ public int getMapOffset() {
+ return mapOffset;
+ }
+
+ public int getDataLength() {
+ return dataLen;
+ }
+
+ public int getMapLength() {
+ return mapLen;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/mac/ResourceMap.java b/src/typecast/net/java/dev/typecast/ot/mac/ResourceMap.java
new file mode 100644
index 000000000..ee98fd8eb
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/mac/ResourceMap.java
@@ -0,0 +1,83 @@
+/*
+ * $Id: ResourceMap.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceMap.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ */
+public class ResourceMap {
+
+ private byte[] headerCopy = new byte[16];
+ private int nextResourceMap;
+ private int fileReferenceNumber;
+ private int attributes;
+ private ResourceType[] types;
+
+ /** Creates new ResourceMap */
+ public ResourceMap(DataInput di) throws IOException {
+ di.readFully(headerCopy);
+ nextResourceMap = di.readInt();
+ fileReferenceNumber = di.readUnsignedShort();
+ attributes = di.readUnsignedShort();
+ int typeOffset = di.readUnsignedShort();
+ int nameOffset = di.readUnsignedShort();
+ int typeCount = di.readUnsignedShort() + 1;
+
+ // Read types
+ types = new ResourceType[typeCount];
+ for (int i = 0; i < typeCount; i++) {
+ types[i] = new ResourceType(di);
+ }
+
+ // Read the references
+ for (int i = 0; i < typeCount; i++) {
+ types[i].readRefs(di);
+ }
+
+ // Read the names
+ for (int i = 0; i < typeCount; i++) {
+ types[i].readNames(di);
+ }
+ }
+
+ public ResourceType getResourceType(String typeName) {
+ for (int i = 0; i < types.length; i++) {
+ String s = types[i].getTypeAsString();
+ if (types[i].getTypeAsString().equals(typeName)) {
+ return types[i];
+ }
+ }
+ return null;
+ }
+
+ public ResourceType getResourceType(int i) {
+ return types[i];
+ }
+
+ public int getResourceTypeCount() {
+ return types.length;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/mac/ResourceReference.java b/src/typecast/net/java/dev/typecast/ot/mac/ResourceReference.java
new file mode 100644
index 000000000..f7f6e0fdf
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/mac/ResourceReference.java
@@ -0,0 +1,81 @@
+/*
+ * $Id: ResourceReference.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceReference.java,v 1.1.1.1 2004-12-05 23:14:32 davidsch Exp $
+ */
+public class ResourceReference {
+
+ private int id;
+ private short nameOffset;
+ private short attributes;
+ private int dataOffset;
+ private int handle;
+ private String name;
+
+ /** Creates new ResourceReference */
+ protected ResourceReference(DataInput di) throws IOException {
+ id = di.readUnsignedShort();
+ nameOffset = di.readShort();
+ attributes = (short) di.readUnsignedByte();
+ dataOffset = (di.readUnsignedByte()<<16) | di.readUnsignedShort();
+ handle = di.readInt();
+ }
+
+ protected void readName(DataInput di) throws IOException {
+ if (nameOffset > -1) {
+ int len = di.readUnsignedByte();
+ byte[] buf = new byte[len];
+ di.readFully(buf);
+ name = new String(buf);
+ }
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public short getNameOffset() {
+ return nameOffset;
+ }
+
+ public short getAttributes() {
+ return attributes;
+ }
+
+ public int getDataOffset() {
+ return dataOffset;
+ }
+
+ public int getHandle() {
+ return handle;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/mac/ResourceType.java b/src/typecast/net/java/dev/typecast/ot/mac/ResourceType.java
new file mode 100644
index 000000000..2c21e7a27
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/mac/ResourceType.java
@@ -0,0 +1,82 @@
+/*
+ * $Id: ResourceType.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.mac;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ResourceType.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public class ResourceType {
+
+ private int type;
+ private int count;
+ private int offset;
+ private ResourceReference[] references;
+
+ /** Creates new ResourceType */
+ protected ResourceType(DataInput di) throws IOException {
+ type = di.readInt();
+ count = di.readUnsignedShort() + 1;
+ offset = di.readUnsignedShort();
+ references = new ResourceReference[count];
+ }
+
+ protected void readRefs(DataInput di) throws IOException {
+ for (int i = 0; i < count; i++) {
+ references[i] = new ResourceReference(di);
+ }
+ }
+
+ protected void readNames(DataInput di) throws IOException {
+ for (int i = 0; i < count; i++) {
+ references[i].readName(di);
+ }
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public String getTypeAsString() {
+ return new StringBuffer()
+ .append((char)((type>>24)&0xff))
+ .append((char)((type>>16)&0xff))
+ .append((char)((type>>8)&0xff))
+ .append((char)((type)&0xff))
+ .toString();
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public ResourceReference getReference(int i) {
+ return references[i];
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/BaseTable.java b/src/typecast/net/java/dev/typecast/ot/table/BaseTable.java
new file mode 100644
index 000000000..f92de718f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/BaseTable.java
@@ -0,0 +1,435 @@
+/*
+ * $Id: BaseTable.java,v 1.3 2007-02-08 04:31:31 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Baseline Table
+ * @version $Id: BaseTable.java,v 1.3 2007-02-08 04:31:31 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class BaseTable implements Table {
+
+ private abstract class BaseCoord {
+
+ public abstract int getBaseCoordFormat();
+
+ public abstract short getCoordinate();
+ }
+
+ private class BaseCoordFormat1 extends BaseCoord {
+
+ private short _coordinate;
+
+ protected BaseCoordFormat1(DataInput di) throws IOException {
+ _coordinate = di.readShort();
+ }
+
+ public int getBaseCoordFormat() {
+ return 1;
+ }
+
+ public short getCoordinate() {
+ return _coordinate;
+ }
+
+ }
+
+ private class BaseCoordFormat2 extends BaseCoord {
+
+ private short _coordinate;
+ private int _referenceGlyph;
+ private int _baseCoordPoint;
+
+ protected BaseCoordFormat2(DataInput di) throws IOException {
+ _coordinate = di.readShort();
+ _referenceGlyph = di.readUnsignedShort();
+ _baseCoordPoint = di.readUnsignedShort();
+ }
+
+ public int getBaseCoordFormat() {
+ return 2;
+ }
+
+ public short getCoordinate() {
+ return _coordinate;
+ }
+
+ }
+
+ private class BaseCoordFormat3 extends BaseCoord {
+
+ private short _coordinate;
+ private int _deviceTableOffset;
+
+ protected BaseCoordFormat3(DataInput di) throws IOException {
+ _coordinate = di.readShort();
+ _deviceTableOffset = di.readUnsignedShort();
+ }
+
+ public int getBaseCoordFormat() {
+ return 2;
+ }
+
+ public short getCoordinate() {
+ return _coordinate;
+ }
+
+ }
+
+ private class FeatMinMaxRecord {
+
+ private int _tag;
+ private int _minCoordOffset;
+ private int _maxCoordOffset;
+
+ protected FeatMinMaxRecord(DataInput di) throws IOException {
+ _tag = di.readInt();
+ _minCoordOffset = di.readUnsignedShort();
+ _maxCoordOffset = di.readUnsignedShort();
+ }
+ }
+
+ private class MinMax {
+
+ private int _minCoordOffset;
+ private int _maxCoordOffset;
+ private int _featMinMaxCount;
+ private FeatMinMaxRecord[] _featMinMaxRecord;
+
+ protected MinMax(int minMaxOffset) throws IOException {
+ DataInput di = getDataInputForOffset(minMaxOffset);
+ _minCoordOffset = di.readUnsignedShort();
+ _maxCoordOffset = di.readUnsignedShort();
+ _featMinMaxCount = di.readUnsignedShort();
+ _featMinMaxRecord = new FeatMinMaxRecord[_featMinMaxCount];
+ for (int i = 0; i < _featMinMaxCount; ++i) {
+ _featMinMaxRecord[i] = new FeatMinMaxRecord(di);
+ }
+ }
+ }
+
+ private class BaseValues {
+
+ private int _defaultIndex;
+ private int _baseCoordCount;
+ private int[] _baseCoordOffset;
+ private BaseCoord[] _baseCoords;
+
+ protected BaseValues(int baseValuesOffset) throws IOException {
+ DataInput di = getDataInputForOffset(baseValuesOffset);
+ _defaultIndex = di.readUnsignedShort();
+ _baseCoordCount = di.readUnsignedShort();
+ _baseCoordOffset = new int[_baseCoordCount];
+ for (int i = 0; i < _baseCoordCount; ++i) {
+ _baseCoordOffset[i] = di.readUnsignedShort();
+ }
+ _baseCoords = new BaseCoord[_baseCoordCount];
+ for (int i = 0; i < _baseCoordCount; ++i) {
+ int format = di.readUnsignedShort();
+ switch (format) {
+ case 1:
+ _baseCoords[i] = new BaseCoordFormat1(di);
+ break;
+ case 2:
+ _baseCoords[i] = new BaseCoordFormat2(di);
+ break;
+ case 3:
+ _baseCoords[i] = new BaseCoordFormat3(di);
+ break;
+ }
+ }
+ }
+ }
+
+ private class BaseLangSysRecord {
+
+ private int _baseLangSysTag;
+ private int _minMaxOffset;
+
+ protected BaseLangSysRecord(DataInput di) throws IOException {
+ _baseLangSysTag = di.readInt();
+ _minMaxOffset = di.readUnsignedShort();
+ }
+
+ public int getBaseLangSysTag() {
+ return _baseLangSysTag;
+ }
+
+ public int getMinMaxOffset() {
+ return _minMaxOffset;
+ }
+ }
+
+ private class BaseScript {
+
+ private int _thisOffset;
+ private int _baseValuesOffset;
+ private int _defaultMinMaxOffset;
+ private int _baseLangSysCount;
+ private BaseLangSysRecord[] _baseLangSysRecord;
+ private BaseValues _baseValues;
+ private MinMax[] _minMax;
+
+ protected BaseScript(int baseScriptOffset) throws IOException {
+ _thisOffset = baseScriptOffset;
+ DataInput di = getDataInputForOffset(baseScriptOffset);
+ _baseValuesOffset = di.readUnsignedShort();
+ _defaultMinMaxOffset = di.readUnsignedShort();
+ _baseLangSysCount = di.readUnsignedShort();
+ _baseLangSysRecord = new BaseLangSysRecord[_baseLangSysCount];
+ for (int i = 0; i < _baseLangSysCount; ++i) {
+ _baseLangSysRecord[i] = new BaseLangSysRecord(di);
+ }
+ if (_baseValuesOffset > 0) {
+ _baseValues = new BaseValues(baseScriptOffset + _baseValuesOffset);
+ }
+ for (int i = 0; i < _baseLangSysCount; ++i) {
+ _minMax[i] = new MinMax(baseScriptOffset + _baseLangSysRecord[i].getMinMaxOffset());
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("\nBaseScript BaseScriptT").append(Integer.toHexString(_thisOffset))
+ .append("\nBaseValuesT").append(Integer.toHexString(_thisOffset + _baseValuesOffset))
+ .append("\nMinMaxT").append(Integer.toHexString(_thisOffset + _defaultMinMaxOffset))
+ .append("\n").append(Integer.toHexString(_baseLangSysCount));
+// for (int i = 0; i < _baseLangSysCount; ++i) {
+// sb.append("\n ; BaseScriptRecord[").append(i);
+// sb.append("]\n'").append(tagAsString(_baseScriptRecord[i].getBaseScriptTag())).append("'");
+// sb.append("\nBaseScriptT").append(Integer.toHexString(_thisOffset + _baseScriptRecord[i].getBaseScriptOffset()));
+// }
+// for (int i = 0; i < _baseScriptCount; ++i) {
+// sb.append("\n").append(_baseScripts[i].toString());
+// }
+ if (_baseValues != null) {
+ sb.append("\n").append(_baseValues.toString());
+ }
+ return sb.toString();
+ }
+ }
+
+ private class BaseScriptRecord {
+
+ private int _baseScriptTag;
+ private int _baseScriptOffset;
+
+ protected BaseScriptRecord(DataInput di) throws IOException {
+ _baseScriptTag = di.readInt();
+ _baseScriptOffset = di.readUnsignedShort();
+ }
+
+ public int getBaseScriptTag() {
+ return _baseScriptTag;
+ }
+
+ public int getBaseScriptOffset() {
+ return _baseScriptOffset;
+ }
+ }
+
+ private class BaseScriptList {
+
+ private int _thisOffset;
+ private int _baseScriptCount;
+ private BaseScriptRecord[] _baseScriptRecord;
+ private BaseScript[] _baseScripts;
+
+ protected BaseScriptList(int baseScriptListOffset) throws IOException {
+ _thisOffset = baseScriptListOffset;
+ DataInput di = getDataInputForOffset(baseScriptListOffset);
+ _baseScriptCount = di.readUnsignedShort();
+ _baseScriptRecord = new BaseScriptRecord[_baseScriptCount];
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ _baseScriptRecord[i] = new BaseScriptRecord(di);
+ }
+ _baseScripts = new BaseScript[_baseScriptCount];
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ _baseScripts[i] = new BaseScript(
+ baseScriptListOffset + _baseScriptRecord[i].getBaseScriptOffset());
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("\nBaseScriptList BaseScriptListT").append(Integer.toHexString(_thisOffset))
+ .append("\n").append(Integer.toHexString(_baseScriptCount));
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ sb.append("\n ; BaseScriptRecord[").append(i);
+ sb.append("]\n'").append(tagAsString(_baseScriptRecord[i].getBaseScriptTag())).append("'");
+ sb.append("\nBaseScriptT").append(Integer.toHexString(_thisOffset + _baseScriptRecord[i].getBaseScriptOffset()));
+ }
+ for (int i = 0; i < _baseScriptCount; ++i) {
+ sb.append("\n").append(_baseScripts[i].toString());
+ }
+ return sb.toString();
+ }
+ }
+
+ private class BaseTagList {
+
+ private int _thisOffset;
+ private int _baseTagCount;
+ private int[] _baselineTag;
+
+ protected BaseTagList(int baseTagListOffset) throws IOException {
+ _thisOffset = baseTagListOffset;
+ DataInput di = getDataInputForOffset(baseTagListOffset);
+ _baseTagCount = di.readUnsignedShort();
+ _baselineTag = new int[_baseTagCount];
+ for (int i = 0; i < _baseTagCount; ++i) {
+ _baselineTag[i] = di.readInt();
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("\nBaseTagList BaseTagListT").append(Integer.toHexString(_thisOffset))
+ .append("\n").append(Integer.toHexString(_baseTagCount));
+ for (int i = 0; i < _baseTagCount; ++i) {
+ sb.append("\n'").append(tagAsString(_baselineTag[i])).append("'");
+ }
+ return sb.toString();
+ }
+ }
+
+ private class Axis {
+
+ private int _thisOffset;
+ private int _baseTagListOffset;
+ private int _baseScriptListOffset;
+ private BaseTagList _baseTagList;
+ private BaseScriptList _baseScriptList;
+
+ protected Axis(int axisOffset) throws IOException {
+ _thisOffset = axisOffset;
+ DataInput di = getDataInputForOffset(axisOffset);
+ _baseTagListOffset = di.readUnsignedShort();
+ _baseScriptListOffset = di.readUnsignedShort();
+ if (_baseTagListOffset != 0) {
+ _baseTagList = new BaseTagList(axisOffset + _baseTagListOffset);
+ }
+ if (_baseScriptListOffset != 0) {
+ _baseScriptList = new BaseScriptList(
+ axisOffset + _baseScriptListOffset);
+ }
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("\nAxis AxisT").append(Integer.toHexString(_thisOffset))
+ .append("\nBaseTagListT").append(Integer.toHexString(_thisOffset + _baseTagListOffset))
+ .append("\nBaseScriptListT").append(Integer.toHexString(_thisOffset + _baseScriptListOffset))
+ .append("\n").append(_baseTagList)
+ .append("\n").append(_baseScriptList)
+ .toString();
+ }
+ }
+
+ private DirectoryEntry _de;
+ private int _version;
+ private int _horizAxisOffset;
+ private int _vertAxisOffset;
+ private Axis _horizAxis;
+ private Axis _vertAxis;
+ private byte[] _buf;
+
+ /** Creates a new instance of BaseTable */
+ protected BaseTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+
+ // Load entire table into a buffer, and create another input stream
+ _buf = new byte[de.getLength()];
+ di.readFully(_buf);
+ DataInput di2 = getDataInputForOffset(0);
+
+ _version = di2.readInt();
+ _horizAxisOffset = di2.readUnsignedShort();
+ _vertAxisOffset = di2.readUnsignedShort();
+ if (_horizAxisOffset != 0) {
+ _horizAxis = new Axis(_horizAxisOffset);
+ }
+ if (_vertAxisOffset != 0) {
+ _vertAxis = new Axis(_vertAxisOffset);
+ }
+
+ // Let go of the buffer
+ _buf = null;
+ }
+
+ private DataInput getDataInputForOffset(int offset) {
+ return new DataInputStream(new ByteArrayInputStream(
+ _buf, offset,
+ _de.getLength() - offset));
+ }
+
+// private String valueAsShortHex(int value) {
+// return String.format("%1$4x", value);
+// }
+//
+// private String valueAsLongHex(int value) {
+// return String.format("%1$8x", value);
+// }
+
+ static protected String tagAsString(int tag) {
+ char[] c = new char[4];
+ c[0] = (char)((tag >> 24) & 0xff);
+ c[1] = (char)((tag >> 16) & 0xff);
+ c[2] = (char)((tag >> 8) & 0xff);
+ c[3] = (char)(tag & 0xff);
+ return String.valueOf(c);
+ }
+
+ public int getType() {
+ return BASE;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("; 'BASE' Table - Baseline\n;-------------------------------------\n\n")
+ .append("BASEHeader BASEHeaderT").append(Integer.toHexString(0))
+ .append("\n").append(Integer.toHexString(_version))
+ .append("\nAxisT").append(Integer.toHexString(_horizAxisOffset))
+ .append("\nAxisT").append(Integer.toHexString(_vertAxisOffset));
+ if (_horizAxis != null) {
+ sb.append("\n").append(_horizAxis.toString());
+ }
+ if (_vertAxis != null) {
+ sb.append("\n").append(_vertAxis.toString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CffStandardStrings.java b/src/typecast/net/java/dev/typecast/ot/table/CffStandardStrings.java
new file mode 100644
index 000000000..987ea886c
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CffStandardStrings.java
@@ -0,0 +1,424 @@
+/*
+ * $Id: CffStandardStrings.java,v 1.1 2007-02-05 12:41:52 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * Compact Font Format Standard Strings. As per Appendix A of the Adobe
+ * CFF specification.
+ * @version $Id: CffStandardStrings.java,v 1.1 2007-02-05 12:41:52 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CffStandardStrings {
+
+ public static final String[] standardStrings = {
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold"
+ };
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CffTable.java b/src/typecast/net/java/dev/typecast/ot/table/CffTable.java
new file mode 100644
index 000000000..2bd0cec63
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CffTable.java
@@ -0,0 +1,620 @@
+/*
+ * $Id: CffTable.java,v 1.4 2007-07-26 11:15:06 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * Compact Font Format Table
+ * @version $Id: CffTable.java,v 1.4 2007-07-26 11:15:06 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CffTable implements Table {
+
+ public class Dict {
+
+ private Dictionary<Integer, Object> _entries = new Hashtable<Integer, Object>();
+ private int[] _data;
+ private int _index;
+
+ protected Dict(int[] data, int offset, int length) {
+ _data = data;
+ _index = offset;
+ while (_index < offset + length) {
+ addKeyAndValueEntry();
+ }
+ }
+
+ public Object getValue(int key) {
+ return _entries.get(key);
+ }
+
+ private boolean addKeyAndValueEntry() {
+ ArrayList<Object> operands = new ArrayList<Object>();
+ Object operand = null;
+ while (isOperandAtIndex()) {
+ operand = nextOperand();
+ operands.add(operand);
+ }
+ int operator = _data[_index++];
+ if (operator == 12) {
+ operator <<= 8;
+ operator |= _data[_index++];
+ }
+ if (operands.size() == 1) {
+ _entries.put(operator, operand);
+ } else {
+ _entries.put(operator, operands);
+ }
+ return true;
+ }
+
+ private boolean isOperandAtIndex() {
+ int b0 = _data[_index];
+ if ((32 <= b0 && b0 <= 254)
+ || b0 == 28
+ || b0 == 29
+ || b0 == 30) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isOperatorAtIndex() {
+ int b0 = _data[_index];
+ if (0 <= b0 && b0 <= 21) {
+ return true;
+ }
+ return false;
+ }
+
+ private Object nextOperand() {
+ int b0 = _data[_index];
+ if (32 <= b0 && b0 <= 246) {
+
+ // 1 byte integer
+ ++_index;
+ return new Integer(b0 - 139);
+ } else if (247 <= b0 && b0 <= 250) {
+
+ // 2 byte integer
+ int b1 = _data[_index + 1];
+ _index += 2;
+ return new Integer((b0 - 247) * 256 + b1 + 108);
+ } else if (251 <= b0 && b0 <= 254) {
+
+ // 2 byte integer
+ int b1 = _data[_index + 1];
+ _index += 2;
+ return new Integer(-(b0 - 251) * 256 - b1 - 108);
+ } else if (b0 == 28) {
+
+ // 3 byte integer
+ int b1 = _data[_index + 1];
+ int b2 = _data[_index + 2];
+ _index += 3;
+ return new Integer(b1 << 8 | b2);
+ } else if (b0 == 29) {
+
+ // 5 byte integer
+ int b1 = _data[_index + 1];
+ int b2 = _data[_index + 2];
+ int b3 = _data[_index + 3];
+ int b4 = _data[_index + 4];
+ _index += 5;
+ return new Integer(b1 << 24 | b2 << 16 | b3 << 8 | b4);
+ } else if (b0 == 30) {
+
+ // Real number
+ StringBuffer fString = new StringBuffer();
+ int nibble1 = 0;
+ int nibble2 = 0;
+ ++_index;
+ while ((nibble1 != 0xf) && (nibble2 != 0xf)) {
+ nibble1 = _data[_index] >> 4;
+ nibble2 = _data[_index] & 0xf;
+ ++_index;
+ fString.append(decodeRealNibble(nibble1));
+ fString.append(decodeRealNibble(nibble2));
+ }
+ return new Float(fString.toString());
+ } else {
+ return null;
+ }
+ }
+
+ private String decodeRealNibble(int nibble) {
+ if (nibble < 0xa) {
+ return Integer.toString(nibble);
+ } else if (nibble == 0xa) {
+ return ".";
+ } else if (nibble == 0xb) {
+ return "E";
+ } else if (nibble == 0xc) {
+ return "E-";
+ } else if (nibble == 0xe) {
+ return "-";
+ }
+ return "";
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ Enumeration<Integer> keys = _entries.keys();
+ while (keys.hasMoreElements()) {
+ Integer key = keys.nextElement();
+ if ((key.intValue() & 0xc00) == 0xc00) {
+ sb.append("12 ").append(key.intValue() & 0xff).append(": ");
+ } else {
+ sb.append(key.toString()).append(": ");
+ }
+ sb.append(_entries.get(key).toString()).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ public class Index {
+
+ private int _count;
+ private int _offSize;
+ private int[] _offset;
+ private int[] _data;
+
+ protected Index(DataInput di) throws IOException {
+ _count = di.readUnsignedShort();
+ _offset = new int[_count + 1];
+ _offSize = di.readUnsignedByte();
+ for (int i = 0; i < _count + 1; ++i) {
+ int thisOffset = 0;
+ for (int j = 0; j < _offSize; ++j) {
+ thisOffset |= di.readUnsignedByte() << ((_offSize - j - 1) * 8);
+ }
+ _offset[i] = thisOffset;
+ }
+ _data = new int[getDataLength()];
+ for (int i = 0; i < getDataLength(); ++i) {
+ _data[i] = di.readUnsignedByte();
+ }
+ }
+
+ public int getCount() {
+ return _count;
+ }
+
+ public int getOffset(int index) {
+ return _offset[index];
+ }
+
+ public int getDataLength() {
+ return _offset[_offset.length - 1] - 1;
+ }
+
+ public int[] getData() {
+ return _data;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("DICT\n");
+ sb.append("count: ").append(_count).append("\n");
+ sb.append("offSize: ").append(_offSize).append("\n");
+ for (int i = 0; i < _count + 1; ++i) {
+ sb.append("offset[").append(i).append("]: ").append(_offset[i]).append("\n");
+ }
+ sb.append("data:");
+ for (int i = 0; i < _data.length; ++i) {
+ if (i % 8 == 0) {
+ sb.append("\n");
+ } else {
+ sb.append(" ");
+ }
+ sb.append(_data[i]);
+ }
+ sb.append("\n");
+ return sb.toString();
+ }
+ }
+
+ public class TopDictIndex extends Index {
+
+ protected TopDictIndex(DataInput di) throws IOException {
+ super(di);
+ }
+
+ public Dict getTopDict(int index) {
+ int offset = getOffset(index) - 1;
+ int len = getOffset(index + 1) - offset - 1;
+ return new Dict(getData(), offset, len);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < getCount(); ++i) {
+ sb.append(getTopDict(i).toString()).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ public class NameIndex extends Index {
+
+ protected NameIndex(DataInput di) throws IOException {
+ super(di);
+ }
+
+ public String getName(int index) {
+ String name = null;
+ int offset = getOffset(index) - 1;
+ int len = getOffset(index + 1) - offset - 1;
+
+ // Ensure the name hasn't been deleted
+ if (getData()[offset] != 0) {
+ StringBuffer sb = new StringBuffer();
+ for (int i = offset; i < offset + len; ++i) {
+ sb.append((char) getData()[i]);
+ }
+ name = sb.toString();
+ } else {
+ name = "DELETED NAME";
+ }
+ return name;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < getCount(); ++i) {
+ sb.append(getName(i)).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ public class StringIndex extends Index {
+
+ protected StringIndex(DataInput di) throws IOException {
+ super(di);
+ }
+
+ public String getString(int index) {
+ if (index < CffStandardStrings.standardStrings.length) {
+ return CffStandardStrings.standardStrings[index];
+ } else {
+ index -= CffStandardStrings.standardStrings.length;
+ if (index >= getCount()) {
+ return null;
+ }
+ int offset = getOffset(index) - 1;
+ int len = getOffset(index + 1) - offset - 1;
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = offset; i < offset + len; ++i) {
+ sb.append((char) getData()[i]);
+ }
+ return sb.toString();
+ }
+ }
+
+ public String toString() {
+ int nonStandardBase = CffStandardStrings.standardStrings.length;
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < getCount(); ++i) {
+ sb.append(nonStandardBase + i).append(": ");
+ sb.append(getString(nonStandardBase + i)).append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ private class CharsetRange {
+
+ private int _first;
+ private int _left;
+
+ public int getFirst() {
+ return _first;
+ }
+
+ protected void setFirst(int first) {
+ _first = first;
+ }
+
+ public int getLeft() {
+ return _left;
+ }
+
+ protected void setLeft(int left) {
+ _left = left;
+ }
+ }
+
+ private class CharsetRange1 extends CharsetRange {
+
+ protected CharsetRange1(DataInput di) throws IOException {
+ setFirst(di.readUnsignedShort());
+ setLeft(di.readUnsignedByte());
+ }
+ }
+
+ private class CharsetRange2 extends CharsetRange {
+
+ protected CharsetRange2(DataInput di) throws IOException {
+ setFirst(di.readUnsignedShort());
+ setLeft(di.readUnsignedShort());
+ }
+ }
+
+ private abstract class Charset {
+
+ public abstract int getFormat();
+
+ public abstract int getSID(int gid);
+ }
+
+ private class CharsetFormat0 extends Charset {
+
+ private int[] _glyph;
+
+ protected CharsetFormat0(DataInput di, int glyphCount) throws IOException {
+ _glyph = new int[glyphCount - 1]; // minus 1 because .notdef is omitted
+ for (int i = 0; i < glyphCount - 1; ++i) {
+ _glyph[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getFormat() {
+ return 0;
+ }
+
+ public int getSID(int gid) {
+ if (gid == 0) {
+ return 0;
+ }
+ return _glyph[gid - 1];
+ }
+ }
+
+ private class CharsetFormat1 extends Charset {
+
+ private ArrayList<CharsetRange> _charsetRanges = new ArrayList<CharsetRange>();
+
+ protected CharsetFormat1(DataInput di, int glyphCount) throws IOException {
+ int glyphsCovered = glyphCount - 1; // minus 1 because .notdef is omitted
+ while (glyphsCovered > 0) {
+ CharsetRange range = new CharsetRange1(di);
+ _charsetRanges.add(range);
+ glyphsCovered -= range.getLeft() + 1;
+ }
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+ public int getSID(int gid) {
+ if (gid == 0) {
+ return 0;
+ }
+
+ // Count through the ranges to find the one of interest
+ int count = 0;
+ for (CharsetRange range : _charsetRanges) {
+ count += range.getLeft();
+ if (gid < count) {
+ int sid = gid - count + range.getFirst();
+ return sid;
+ }
+ }
+ return 0;
+ }
+ }
+
+ private class CharsetFormat2 extends Charset {
+
+ private ArrayList<CharsetRange> _charsetRanges = new ArrayList<CharsetRange>();
+
+ protected CharsetFormat2(DataInput di, int glyphCount) throws IOException {
+ int glyphsCovered = glyphCount - 1; // minus 1 because .notdef is omitted
+ while (glyphsCovered > 0) {
+ CharsetRange range = new CharsetRange2(di);
+ _charsetRanges.add(range);
+ glyphsCovered -= range.getLeft() + 1;
+ }
+ }
+
+ public int getFormat() {
+ return 2;
+ }
+
+ public int getSID(int gid) {
+ if (gid == 0) {
+ return 0;
+ }
+
+ // Count through the ranges to find the one of interest
+ int count = 0;
+ for (CharsetRange range : _charsetRanges) {
+ if (gid < range.getLeft() + count) {
+ int sid = gid - count + range.getFirst() - 1;
+ return sid;
+ }
+ count += range.getLeft();
+ }
+ return 0;
+ }
+ }
+
+ private DirectoryEntry _de;
+ private int _major;
+ private int _minor;
+ private int _hdrSize;
+ private int _offSize;
+ private NameIndex _nameIndex;
+ private TopDictIndex _topDictIndex;
+ private StringIndex _stringIndex;
+ private Index _globalSubrIndex;
+ private Index _charStringsIndexArray[];
+ private Charset[] _charsets;
+ private Charstring[][] _charstringsArray;
+
+ private byte[] _buf;
+
+ /** Creates a new instance of CffTable */
+ protected CffTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+
+ // Load entire table into a buffer, and create another input stream
+ _buf = new byte[de.getLength()];
+ di.readFully(_buf);
+ DataInput di2 = getDataInputForOffset(0);
+
+ // Header
+ _major = di2.readUnsignedByte();
+ _minor = di2.readUnsignedByte();
+ _hdrSize = di2.readUnsignedByte();
+ _offSize = di2.readUnsignedByte();
+
+ // Name INDEX
+ di2 = getDataInputForOffset(_hdrSize);
+ _nameIndex = new NameIndex(di2);
+
+ // Top DICT INDEX
+ _topDictIndex = new TopDictIndex(di2);
+
+ // String INDEX
+ _stringIndex = new StringIndex(di2);
+
+ // Global Subr INDEX
+ _globalSubrIndex = new Index(di2);
+
+ // Encodings go here -- but since this is an OpenType font will this
+ // not always be a CIDFont? In which case there are no encodings
+ // within the CFF data.
+
+ // Load each of the fonts
+ _charStringsIndexArray = new Index[_topDictIndex.getCount()];
+ _charsets = new Charset[_topDictIndex.getCount()];
+ _charstringsArray = new Charstring[_topDictIndex.getCount()][];
+ for (int i = 0; i < _topDictIndex.getCount(); ++i) {
+
+ // Charstrings INDEX
+ // We load this before Charsets because we may need to know the number
+ // of glyphs
+ Integer charStringsOffset = (Integer) _topDictIndex.getTopDict(i).getValue(17);
+ di2 = getDataInputForOffset(charStringsOffset);
+ _charStringsIndexArray[i] = new Index(di2);
+ int glyphCount = _charStringsIndexArray[i].getCount();
+
+ // Charsets
+ Integer charsetOffset = (Integer) _topDictIndex.getTopDict(i).getValue(15);
+ di2 = getDataInputForOffset(charsetOffset);
+ int format = di2.readUnsignedByte();
+ switch (format) {
+ case 0:
+ _charsets[i] = new CharsetFormat0(di2, glyphCount);
+ break;
+ case 1:
+ _charsets[i] = new CharsetFormat1(di2, glyphCount);
+ break;
+ case 2:
+ _charsets[i] = new CharsetFormat2(di2, glyphCount);
+ break;
+ }
+
+ // Create the charstrings
+ _charstringsArray[i] = new Charstring[glyphCount];
+ for (int j = 0; j < glyphCount; ++j) {
+ int offset = _charStringsIndexArray[i].getOffset(j) - 1;
+ int len = _charStringsIndexArray[i].getOffset(j + 1) - offset - 1;
+ _charstringsArray[i][j] = new CharstringType2(
+ i,
+ _stringIndex.getString(_charsets[i].getSID(j)),
+ _charStringsIndexArray[i].getData(),
+ offset,
+ len,
+ null,
+ null);
+ }
+ }
+ }
+
+ private DataInput getDataInputForOffset(int offset) {
+ return new DataInputStream(new ByteArrayInputStream(
+ _buf, offset,
+ _de.getLength() - offset));
+ }
+
+ public NameIndex getNameIndex() {
+ return _nameIndex;
+ }
+
+ public Charset getCharset(int fontIndex) {
+ return _charsets[fontIndex];
+ }
+
+ public Charstring getCharstring(int fontIndex, int gid) {
+ return _charstringsArray[fontIndex][gid];
+ }
+
+ public int getCharstringCount(int fontIndex) {
+ return _charstringsArray[fontIndex].length;
+ }
+
+ public int getType() {
+ return CFF;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'CFF' Table - Compact Font Format\n---------------------------------\n");
+ sb.append("\nName INDEX\n");
+ sb.append(_nameIndex.toString());
+ sb.append("\nTop DICT INDEX\n");
+ sb.append(_topDictIndex.toString());
+ sb.append("\nString INDEX\n");
+ sb.append(_stringIndex.toString());
+ sb.append("\nGlobal Subr INDEX\n");
+ sb.append(_globalSubrIndex.toString());
+ for (int i = 0; i < _charStringsIndexArray.length; ++i) {
+ sb.append("\nCharStrings INDEX ").append(i).append("\n");
+ sb.append(_charStringsIndexArray[i].toString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Charstring.java b/src/typecast/net/java/dev/typecast/ot/table/Charstring.java
new file mode 100644
index 000000000..2439d6bc5
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Charstring.java
@@ -0,0 +1,33 @@
+/*
+ * $Id: Charstring.java,v 1.2 2007-02-21 12:25:19 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * CFF Charstring
+ * @version $Id: Charstring.java,v 1.2 2007-02-21 12:25:19 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public abstract class Charstring {
+
+ public abstract int getIndex();
+
+ public abstract String getName();
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CharstringType2.java b/src/typecast/net/java/dev/typecast/ot/table/CharstringType2.java
new file mode 100644
index 000000000..e47825cf3
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CharstringType2.java
@@ -0,0 +1,235 @@
+/*
+ * $Id: CharstringType2.java,v 1.4 2007-07-26 11:13:44 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import net.java.dev.typecast.ot.table.CffTable;
+
+/**
+ * CFF Type 2 Charstring
+ * @version $Id: CharstringType2.java,v 1.4 2007-07-26 11:13:44 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CharstringType2 extends Charstring {
+
+ private static final String[] _oneByteOperators = {
+ "-Reserved-",
+ "hstem",
+ "-Reserved-",
+ "vstem",
+ "vmoveto",
+ "rlineto",
+ "hlineto",
+ "vlineto",
+ "rrcurveto",
+ "-Reserved-",
+ "callsubr",
+ "return",
+ "escape",
+ "-Reserved-",
+ "endchar",
+ "-Reserved-",
+ "-Reserved-",
+ "-Reserved-",
+ "hstemhm",
+ "hintmask",
+ "cntrmask",
+ "rmoveto",
+ "hmoveto",
+ "vstemhm",
+ "rcurveline",
+ "rlinecurve",
+ "vvcurveto",
+ "hhcurveto",
+ "shortint",
+ "callgsubr",
+ "vhcurveto",
+ "hvcurveto"
+ };
+
+ private static final String[] _twoByteOperators = {
+ "-Reserved- (dotsection)",
+ "-Reserved-",
+ "-Reserved-",
+ "and",
+ "or",
+ "not",
+ "-Reserved-",
+ "-Reserved-",
+ "-Reserved-",
+ "abs",
+ "add",
+ "sub",
+ "div",
+ "-Reserved-",
+ "neg",
+ "eq",
+ "-Reserved-",
+ "-Reserved-",
+ "drop",
+ "-Reserved-",
+ "put",
+ "get",
+ "ifelse",
+ "random",
+ "mul",
+ "-Reserved-",
+ "sqrt",
+ "dup",
+ "exch",
+ "index",
+ "roll",
+ "-Reserved-",
+ "-Reserved-",
+ "-Reserved-",
+ "hflex",
+ "flex",
+ "hflex1",
+ "flex1",
+ "-Reserved-"
+ };
+
+ private int _index;
+ private String _name;
+ private int[] _data;
+ private int _offset;
+ private int _length;
+ private CffTable.Index _localSubrIndex;
+ private CffTable.Index _globalSubrIndex;
+ private int _ip;
+
+ /** Creates a new instance of CharstringType2 */
+ protected CharstringType2(
+ int index,
+ String name,
+ int[] data,
+ int offset,
+ int length,
+ CffTable.Index localSubrIndex,
+ CffTable.Index globalSubrIndex) {
+ _index = index;
+ _name = name;
+ _data = data;
+ _offset = offset;
+ _length = length;
+ _localSubrIndex = localSubrIndex;
+ _globalSubrIndex = globalSubrIndex;
+ }
+
+ public int getIndex() {
+ return _index;
+ }
+
+ public String getName() {
+ return _name;
+ }
+
+ private void disassemble(StringBuffer sb) {
+ Number operand = null;
+ while (isOperandAtIndex()) {
+ operand = nextOperand();
+ sb.append(operand).append(" ");
+ }
+ int operator = nextByte();
+ String mnemonic;
+ if (operator == 12) {
+ operator = nextByte();
+
+ // Check we're not exceeding the upper limit of our mnemonics
+ if (operator > 38) {
+ operator = 38;
+ }
+ mnemonic = _twoByteOperators[operator];
+ } else {
+ mnemonic = _oneByteOperators[operator];
+ }
+ sb.append(mnemonic);
+ }
+
+ public void resetIP() {
+ _ip = _offset;
+ }
+
+ public boolean isOperandAtIndex() {
+ int b0 = _data[_ip];
+ if ((32 <= b0 && b0 <= 255) || b0 == 28) {
+ return true;
+ }
+ return false;
+ }
+
+ public Number nextOperand() {
+ int b0 = _data[_ip];
+ if (32 <= b0 && b0 <= 246) {
+
+ // 1 byte integer
+ ++_ip;
+ return new Integer(b0 - 139);
+ } else if (247 <= b0 && b0 <= 250) {
+
+ // 2 byte integer
+ int b1 = _data[_ip + 1];
+ _ip += 2;
+ return new Integer((b0 - 247) * 256 + b1 + 108);
+ } else if (251 <= b0 && b0 <= 254) {
+
+ // 2 byte integer
+ int b1 = _data[_ip + 1];
+ _ip += 2;
+ return new Integer(-(b0 - 251) * 256 - b1 - 108);
+ } else if (b0 == 28) {
+
+ // 3 byte integer
+ int b1 = _data[_ip + 1];
+ int b2 = _data[_ip + 2];
+ _ip += 3;
+ return new Integer(b1 << 8 | b2);
+ } else if (b0 == 255) {
+
+ // 16-bit signed integer with 16 bits of fraction
+ int b1 = (byte) _data[_ip + 1];
+ int b2 = _data[_ip + 2];
+ int b3 = _data[_ip + 3];
+ int b4 = _data[_ip + 4];
+ _ip += 5;
+ return new Float((b1 << 8 | b2) + ((b3 << 8 | b4) / 65536.0));
+ } else {
+ return null;
+ }
+ }
+
+ public int nextByte() {
+ return _data[_ip++];
+ }
+
+ public boolean moreBytes() {
+ return _ip < _offset + _length;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ resetIP();
+ while (moreBytes()) {
+ disassemble(sb);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ClassDef.java b/src/typecast/net/java/dev/typecast/ot/table/ClassDef.java
new file mode 100644
index 000000000..9fa45c3c6
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ClassDef.java
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ClassDef.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public abstract class ClassDef {
+
+ public abstract int getFormat();
+
+ protected static ClassDef read(RandomAccessFile raf) throws IOException {
+ ClassDef c = null;
+ int format = raf.readUnsignedShort();
+ if (format == 1) {
+ c = new ClassDefFormat1(raf);
+ } else if (format == 2) {
+ c = new ClassDefFormat2(raf);
+ }
+ return c;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat1.java b/src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat1.java
new file mode 100644
index 000000000..07b85ddf9
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat1.java
@@ -0,0 +1,39 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ClassDefFormat1.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public class ClassDefFormat1 extends ClassDef {
+
+ private int startGlyph;
+ private int glyphCount;
+ private int[] classValues;
+
+ /** Creates new ClassDefFormat1 */
+ public ClassDefFormat1(RandomAccessFile raf) throws IOException {
+ startGlyph = raf.readUnsignedShort();
+ glyphCount = raf.readUnsignedShort();
+ classValues = new int[glyphCount];
+ for (int i = 0; i < glyphCount; i++) {
+ classValues[i] = raf.readUnsignedShort();
+ }
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat2.java b/src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat2.java
new file mode 100644
index 000000000..f8b883c41
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ClassDefFormat2.java
@@ -0,0 +1,37 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ClassDefFormat2.java,v 1.1.1.1 2004-12-05 23:14:33 davidsch Exp $
+ */
+public class ClassDefFormat2 extends ClassDef {
+
+ private int classRangeCount;
+ private RangeRecord[] classRangeRecords;
+
+ /** Creates new ClassDefFormat2 */
+ public ClassDefFormat2(RandomAccessFile raf) throws IOException {
+ classRangeCount = raf.readUnsignedShort();
+ classRangeRecords = new RangeRecord[classRangeCount];
+ for (int i = 0; i < classRangeCount; i++) {
+ classRangeRecords[i] = new RangeRecord(raf);
+ }
+ }
+
+ public int getFormat() {
+ return 2;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapFormat.java b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat.java
new file mode 100644
index 000000000..be88af1e6
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat.java
@@ -0,0 +1,134 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CmapFormat.java,v 1.3 2004-12-21 16:56:35 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public abstract class CmapFormat {
+
+ public class Range {
+
+ private int _startCode;
+ private int _endCode;
+
+ protected Range(int startCode, int endCode) {
+ _startCode = startCode;
+ _endCode = endCode;
+ }
+
+ public int getStartCode() {
+ return _startCode;
+ }
+
+ public int getEndCode() {
+ return _endCode;
+ }
+ }
+
+ protected int _format;
+ protected int _length;
+ protected int _language;
+
+ protected CmapFormat(DataInput di) throws IOException {
+ _length = di.readUnsignedShort();
+ _language = di.readUnsignedShort();
+ }
+
+ protected static CmapFormat create(int format, DataInput di)
+ throws IOException {
+ switch(format) {
+ case 0:
+ return new CmapFormat0(di);
+ case 2:
+ return new CmapFormat2(di);
+ case 4:
+ return new CmapFormat4(di);
+ case 6:
+ return new CmapFormat6(di);
+ default:
+ return new CmapFormatUnknown(format, di);
+ }
+ }
+
+ public int getFormat() {
+ return _format;
+ }
+
+ public int getLength() {
+ return _length;
+ }
+
+ public int getLanguage() {
+ return _language;
+ }
+
+ public abstract int getRangeCount();
+
+ public abstract Range getRange(int index)
+ throws ArrayIndexOutOfBoundsException;
+
+ public abstract int mapCharCode(int charCode);
+
+ public String toString() {
+ return new StringBuffer()
+ .append("format: ")
+ .append(_format)
+ .append(", length: ")
+ .append(_length)
+ .append(", language: ")
+ .append(_language).toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapFormat0.java b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat0.java
new file mode 100644
index 000000000..80f42b227
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat0.java
@@ -0,0 +1,92 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Simple Macintosh cmap table, mapping only the ASCII character set to glyphs.
+ *
+ * @version $Id: CmapFormat0.java,v 1.2 2004-12-21 10:22:55 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat0 extends CmapFormat {
+
+ private int[] _glyphIdArray = new int[256];
+
+ protected CmapFormat0(DataInput di) throws IOException {
+ super(di);
+ _format = 0;
+ for (int i = 0; i < 256; i++) {
+ _glyphIdArray[i] = di.readUnsignedByte();
+ }
+ }
+
+ public int getRangeCount() {
+ return 1;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ if (index != 0) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return new Range(0, 255);
+ }
+
+ public int mapCharCode(int charCode) {
+ if (0 <= charCode && charCode < 256) {
+ return _glyphIdArray[charCode];
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapFormat2.java b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat2.java
new file mode 100644
index 000000000..4eeaf420a
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat2.java
@@ -0,0 +1,173 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * High-byte mapping through table cmap format.
+ * @version $Id: CmapFormat2.java,v 1.3 2004-12-21 16:56:54 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat2 extends CmapFormat {
+
+ private class SubHeader {
+ int _firstCode;
+ int _entryCount;
+ short _idDelta;
+ int _idRangeOffset;
+ int _arrayIndex;
+ }
+
+ private int[] _subHeaderKeys = new int[256];
+ private SubHeader[] _subHeaders;
+ private int[] _glyphIndexArray;
+
+ protected CmapFormat2(DataInput di) throws IOException {
+ super(di);
+ _format = 2;
+
+ int pos = 6;
+
+ // Read the subheader keys, noting the highest value, as this will
+ // determine the number of subheaders to read.
+ int highest = 0;
+ for (int i = 0; i < 256; ++i) {
+ _subHeaderKeys[i] = di.readUnsignedShort();
+ highest = Math.max(highest, _subHeaderKeys[i]);
+ pos += 2;
+ }
+ int subHeaderCount = highest / 8 + 1;
+ _subHeaders = new SubHeader[subHeaderCount];
+
+ // Read the subheaders, once again noting the highest glyphIndexArray
+ // index range.
+ int indexArrayOffset = 8 * subHeaderCount + 518;
+ highest = 0;
+ for (int i = 0; i < _subHeaders.length; ++i) {
+ SubHeader sh = new SubHeader();
+ sh._firstCode = di.readUnsignedShort();
+ sh._entryCount = di.readUnsignedShort();
+ sh._idDelta = di.readShort();
+ sh._idRangeOffset = di.readUnsignedShort();
+
+ // Calculate the offset into the _glyphIndexArray
+ pos += 8;
+ sh._arrayIndex =
+ (pos - 2 + sh._idRangeOffset - indexArrayOffset) / 2;
+
+ // What is the highest range within the glyphIndexArray?
+ highest = Math.max(highest, sh._arrayIndex + sh._entryCount);
+
+ _subHeaders[i] = sh;
+ }
+
+ // Read the glyphIndexArray
+ _glyphIndexArray = new int[highest];
+ for (int i = 0; i < _glyphIndexArray.length; ++i) {
+ _glyphIndexArray[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getRangeCount() {
+ return _subHeaders.length;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ if (index < 0 || index >= _subHeaders.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ // Find the high-byte (if any)
+ int highByte = 0;
+ if (index != 0) {
+ for (int i = 0; i < 256; ++i) {
+ if (_subHeaderKeys[i] / 8 == index) {
+ highByte = i << 8;
+ break;
+ }
+ }
+ }
+
+ return new Range(
+ highByte | _subHeaders[index]._firstCode,
+ highByte | (_subHeaders[index]._firstCode +
+ _subHeaders[index]._entryCount - 1));
+ }
+
+ public int mapCharCode(int charCode) {
+
+ // Get the appropriate subheader
+ int index = 0;
+ int highByte = charCode >> 8;
+ if (highByte != 0) {
+ index = _subHeaderKeys[highByte] / 8;
+ }
+ SubHeader sh = _subHeaders[index];
+
+ // Is the charCode out-of-range?
+ int lowByte = charCode & 0xff;
+ if (lowByte < sh._firstCode ||
+ lowByte >= (sh._firstCode + sh._entryCount)) {
+ return 0;
+ }
+
+ // Now calculate the glyph index
+ int glyphIndex =
+ _glyphIndexArray[sh._arrayIndex + (lowByte - sh._firstCode)];
+ if (glyphIndex != 0) {
+ glyphIndex += sh._idDelta;
+ glyphIndex %= 65536;
+ }
+ return glyphIndex;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapFormat4.java b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat4.java
new file mode 100644
index 000000000..3748a8f84
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat4.java
@@ -0,0 +1,165 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CmapFormat4.java,v 1.3 2004-12-21 16:57:23 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat4 extends CmapFormat {
+
+ private int _segCountX2;
+ private int _searchRange;
+ private int _entrySelector;
+ private int _rangeShift;
+ private int[] _endCode;
+ private int[] _startCode;
+ private int[] _idDelta;
+ private int[] _idRangeOffset;
+ private int[] _glyphIdArray;
+ private int _segCount;
+
+ protected CmapFormat4(DataInput di) throws IOException {
+ super(di); // 6
+ _format = 4;
+ _segCountX2 = di.readUnsignedShort(); // +2 (8)
+ _segCount = _segCountX2 / 2;
+ _endCode = new int[_segCount];
+ _startCode = new int[_segCount];
+ _idDelta = new int[_segCount];
+ _idRangeOffset = new int[_segCount];
+ _searchRange = di.readUnsignedShort(); // +2 (10)
+ _entrySelector = di.readUnsignedShort(); // +2 (12)
+ _rangeShift = di.readUnsignedShort(); // +2 (14)
+ for (int i = 0; i < _segCount; i++) {
+ _endCode[i] = di.readUnsignedShort();
+ } // + 2*segCount (2*segCount + 14)
+ di.readUnsignedShort(); // reservePad +2 (2*segCount + 16)
+ for (int i = 0; i < _segCount; i++) {
+ _startCode[i] = di.readUnsignedShort();
+ } // + 2*segCount (4*segCount + 16)
+ for (int i = 0; i < _segCount; i++) {
+ _idDelta[i] = di.readUnsignedShort();
+ } // + 2*segCount (6*segCount + 16)
+ for (int i = 0; i < _segCount; i++) {
+ _idRangeOffset[i] = di.readUnsignedShort();
+ } // + 2*segCount (8*segCount + 16)
+
+ // Whatever remains of this header belongs in glyphIdArray
+ int count = (_length - (8*_segCount + 16)) / 2;
+ _glyphIdArray = new int[count];
+ for (int i = 0; i < count; i++) {
+ _glyphIdArray[i] = di.readUnsignedShort();
+ } // + 2*count (8*segCount + 2*count + 18)
+
+ // Are there any padding bytes we need to consume?
+// int leftover = length - (8*segCount + 2*count + 18);
+// if (leftover > 0) {
+// di.skipBytes(leftover);
+// }
+ }
+
+ public int getRangeCount() {
+ return _segCount;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ if (index < 0 || index >= _segCount) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return new Range(_startCode[index], _endCode[index]);
+ }
+
+ public int mapCharCode(int charCode) {
+ try {
+ for (int i = 0; i < _segCount; i++) {
+ if (_endCode[i] >= charCode) {
+ if (_startCode[i] <= charCode) {
+ if (_idRangeOffset[i] > 0) {
+ return _glyphIdArray[_idRangeOffset[i]/2 + (charCode - _startCode[i]) - (_segCount - i)];
+ } else {
+ return (_idDelta[i] + charCode) % 65536;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.err.println("error: Array out of bounds - " + e.getMessage());
+ }
+ return 0;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append(super.toString())
+ .append(", segCountX2: ")
+ .append(_segCountX2)
+ .append(", searchRange: ")
+ .append(_searchRange)
+ .append(", entrySelector: ")
+ .append(_entrySelector)
+ .append(", rangeShift: ")
+ .append(_rangeShift)
+ .append(", endCode: ")
+ .append(_endCode)
+ .append(", startCode: ")
+ .append(_endCode)
+ .append(", idDelta: ")
+ .append(_idDelta)
+ .append(", idRangeOffset: ")
+ .append(_idRangeOffset).toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapFormat6.java b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat6.java
new file mode 100644
index 000000000..f9b398aab
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapFormat6.java
@@ -0,0 +1,87 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * TODO: To be implemented
+ * @version $Id: CmapFormat6.java,v 1.2 2004-12-21 10:22:56 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapFormat6 extends CmapFormat {
+
+ private short _firstCode;
+ private short _entryCount;
+ private short[] _glyphIdArray;
+
+ protected CmapFormat6(DataInput di) throws IOException {
+ super(di);
+ _format = 6;
+
+ // HACK: As this is not yet implemented, we need to skip over the bytes
+ // we should be consuming
+ //di.skipBytes(_length - 4);
+ }
+
+ public int getRangeCount() {
+ return 0;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ public int mapCharCode(int charCode) {
+ return 0;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapFormatUnknown.java b/src/typecast/net/java/dev/typecast/ot/table/CmapFormatUnknown.java
new file mode 100644
index 000000000..01ca600f1
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapFormatUnknown.java
@@ -0,0 +1,54 @@
+/*
+ * $Id: CmapFormatUnknown.java,v 1.1 2004-12-21 10:21:23 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * When we encounter a cmap format we don't understand, we can use this class
+ * to hold the bare minimum information about it.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: CmapFormatUnknown.java,v 1.1 2004-12-21 10:21:23 davidsch Exp $
+ */
+public class CmapFormatUnknown extends CmapFormat {
+
+ /** Creates a new instance of CmapFormatUnknown */
+ protected CmapFormatUnknown(int format, DataInput di) throws IOException {
+ super(di);
+ _format = format;
+
+ // We don't know how to handle this data, so we'll just skip over it
+ di.skipBytes(_length - 4);
+ }
+
+ public int getRangeCount() {
+ return 0;
+ }
+
+ public Range getRange(int index) throws ArrayIndexOutOfBoundsException {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ public int mapCharCode(int charCode) {
+ return 0;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapIndexEntry.java b/src/typecast/net/java/dev/typecast/ot/table/CmapIndexEntry.java
new file mode 100644
index 000000000..c82e270fb
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapIndexEntry.java
@@ -0,0 +1,117 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CmapIndexEntry.java,v 1.2 2004-12-21 10:22:56 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapIndexEntry implements Comparable {
+
+ private int _platformId;
+ private int _encodingId;
+ private int _offset;
+ private CmapFormat _format;
+
+ protected CmapIndexEntry(DataInput di) throws IOException {
+ _platformId = di.readUnsignedShort();
+ _encodingId = di.readUnsignedShort();
+ _offset = di.readInt();
+ }
+
+ public int getPlatformId() {
+ return _platformId;
+ }
+
+ public int getEncodingId() {
+ return _encodingId;
+ }
+
+ public int getOffset() {
+ return _offset;
+ }
+
+ public CmapFormat getFormat() {
+ return _format;
+ }
+
+ public void setFormat(CmapFormat format) {
+ _format = format;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("platform id: ")
+ .append(_platformId)
+ .append(" (")
+ .append(ID.getPlatformName((short) _platformId))
+ .append("), encoding id: ")
+ .append(_encodingId)
+ .append(" (")
+ .append(ID.getEncodingName((short) _platformId, (short) _encodingId))
+ .append("), offset: ")
+ .append(_offset).toString();
+ }
+
+ public int compareTo(java.lang.Object obj) {
+ CmapIndexEntry entry = (CmapIndexEntry) obj;
+ if (getOffset() < entry.getOffset()) {
+ return -1;
+ } else if (getOffset() > entry.getOffset()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CmapTable.java b/src/typecast/net/java/dev/typecast/ot/table/CmapTable.java
new file mode 100644
index 000000000..de69cc1f0
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CmapTable.java
@@ -0,0 +1,161 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import java.util.Arrays;
+
+/**
+ * @version $Id: CmapTable.java,v 1.3 2004-12-21 10:22:56 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CmapTable implements Table {
+
+ private DirectoryEntry _de;
+ private int _version;
+ private int _numTables;
+ private CmapIndexEntry[] _entries;
+
+ protected CmapTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _version = di.readUnsignedShort();
+ _numTables = di.readUnsignedShort();
+ long bytesRead = 4;
+ _entries = new CmapIndexEntry[_numTables];
+
+ // Get each of the index entries
+ for (int i = 0; i < _numTables; i++) {
+ _entries[i] = new CmapIndexEntry(di);
+ bytesRead += 8;
+ }
+
+ // Sort into their order of offset
+ Arrays.sort(_entries);
+
+ // Get each of the tables
+ int lastOffset = 0;
+ CmapFormat lastFormat = null;
+ for (int i = 0; i < _numTables; i++) {
+ if (_entries[i].getOffset() == lastOffset) {
+
+ // This is a multiple entry
+ _entries[i].setFormat(lastFormat);
+ continue;
+ } else if (_entries[i].getOffset() > bytesRead) {
+ di.skipBytes(_entries[i].getOffset() - (int) bytesRead);
+ } else if (_entries[i].getOffset() != bytesRead) {
+
+ // Something is amiss
+ throw new IOException();
+ }
+ int formatType = di.readUnsignedShort();
+ lastFormat = CmapFormat.create(formatType, di);
+ lastOffset = _entries[i].getOffset();
+ _entries[i].setFormat(lastFormat);
+ bytesRead += lastFormat.getLength();
+ }
+ }
+
+ public int getVersion() {
+ return _version;
+ }
+
+ public int getNumTables() {
+ return _numTables;
+ }
+
+ public CmapIndexEntry getCmapIndexEntry(int i) {
+ return _entries[i];
+ }
+
+ public CmapFormat getCmapFormat(short platformId, short encodingId) {
+
+ // Find the requested format
+ for (int i = 0; i < _numTables; i++) {
+ if (_entries[i].getPlatformId() == platformId
+ && _entries[i].getEncodingId() == encodingId) {
+ return _entries[i].getFormat();
+ }
+ }
+ return null;
+ }
+
+ public int getType() {
+ return cmap;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer().append("cmap\n");
+
+ // Get each of the index entries
+ for (int i = 0; i < _numTables; i++) {
+ sb.append("\t").append(_entries[i].toString()).append("\n");
+ }
+
+ // Get each of the tables
+// for (int i = 0; i < numTables; i++) {
+// sb.append("\t").append(formats[i].toString()).append("\n");
+// }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Coverage.java b/src/typecast/net/java/dev/typecast/ot/table/Coverage.java
new file mode 100644
index 000000000..3c6cf0409
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Coverage.java
@@ -0,0 +1,83 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Coverage.java,v 1.3 2007-01-24 09:43:30 davidsch Exp $
+ */
+public abstract class Coverage {
+
+ public abstract int getFormat();
+
+ /**
+ * @param glyphId The ID of the glyph to find.
+ * @return The index of the glyph within the coverage, or -1 if the glyph
+ * can't be found.
+ */
+ public abstract int findGlyph(int glyphId);
+
+ protected static Coverage read(DataInput di) throws IOException {
+ Coverage c = null;
+ int format = di.readUnsignedShort();
+ if (format == 1) {
+ c = new CoverageFormat1(di);
+ } else if (format == 2) {
+ c = new CoverageFormat2(di);
+ }
+ return c;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CoverageFormat1.java b/src/typecast/net/java/dev/typecast/ot/table/CoverageFormat1.java
new file mode 100644
index 000000000..a81eb0f1e
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CoverageFormat1.java
@@ -0,0 +1,88 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: CoverageFormat1.java,v 1.2 2007-01-24 09:43:30 davidsch Exp $
+ */
+public class CoverageFormat1 extends Coverage {
+
+ private int _glyphCount;
+ private int[] _glyphIds;
+
+ /** Creates new CoverageFormat1 */
+ protected CoverageFormat1(DataInput di) throws IOException {
+ _glyphCount = di.readUnsignedShort();
+ _glyphIds = new int[_glyphCount];
+ for (int i = 0; i < _glyphCount; i++) {
+ _glyphIds[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+ public int findGlyph(int glyphId) {
+ for (int i = 0; i < _glyphCount; i++) {
+ if (_glyphIds[i] == glyphId) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CoverageFormat2.java b/src/typecast/net/java/dev/typecast/ot/table/CoverageFormat2.java
new file mode 100644
index 000000000..a30489647
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CoverageFormat2.java
@@ -0,0 +1,89 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: CoverageFormat2.java,v 1.2 2007-01-24 09:43:30 davidsch Exp $
+ */
+public class CoverageFormat2 extends Coverage {
+
+ private int _rangeCount;
+ private RangeRecord[] _rangeRecords;
+
+ /** Creates new CoverageFormat2 */
+ protected CoverageFormat2(DataInput di) throws IOException {
+ _rangeCount = di.readUnsignedShort();
+ _rangeRecords = new RangeRecord[_rangeCount];
+ for (int i = 0; i < _rangeCount; i++) {
+ _rangeRecords[i] = new RangeRecord(di);
+ }
+ }
+
+ public int getFormat() {
+ return 2;
+ }
+
+ public int findGlyph(int glyphId) {
+ for (int i = 0; i < _rangeCount; i++) {
+ int n = _rangeRecords[i].getCoverageIndex(glyphId);
+ if (n > -1) {
+ return n;
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/CvtTable.java b/src/typecast/net/java/dev/typecast/ot/table/CvtTable.java
new file mode 100644
index 000000000..44dc0af41
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/CvtTable.java
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: CvtTable.java,v 1.1.1.1 2004-12-05 23:14:36 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class CvtTable implements Table {
+
+ private DirectoryEntry de;
+ private short[] values;
+
+ protected CvtTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ int len = de.getLength() / 2;
+ values = new short[len];
+ for (int i = 0; i < len; i++) {
+ values[i] = di.readShort();
+ }
+ }
+
+ public int getType() {
+ return cvt;
+ }
+
+ public short[] getValues() {
+ return values;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'cvt ' Table - Control Value Table\n----------------------------------\n");
+ sb.append("Size = ").append(0).append(" bytes, ").append(values.length).append(" entries\n");
+ sb.append(" Values\n ------\n");
+ for (int i = 0; i < values.length; i++) {
+ sb.append(" ").append(i).append(": ").append(values[i]).append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Device.java b/src/typecast/net/java/dev/typecast/ot/table/Device.java
new file mode 100644
index 000000000..75c302acd
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Device.java
@@ -0,0 +1,50 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Device.java,v 1.1.1.1 2004-12-05 23:14:37 davidsch Exp $
+ */
+public class Device extends Object {
+
+ private int startSize;
+ private int endSize;
+ private int deltaFormat;
+ private int[] deltaValues;
+
+ /** Creates new Device */
+ public Device(RandomAccessFile raf) throws IOException {
+ startSize = raf.readUnsignedShort();
+ endSize = raf.readUnsignedShort();
+ deltaFormat = raf.readUnsignedShort();
+ int size = startSize - endSize;
+ switch (deltaFormat) {
+ case 1:
+ size = (size % 8 == 0) ? size / 8 : size / 8 + 1;
+ break;
+ case 2:
+ size = (size % 4 == 0) ? size / 4 : size / 4 + 1;
+ break;
+ case 3:
+ size = (size % 2 == 0) ? size / 2 : size / 2 + 1;
+ break;
+ }
+ deltaValues = new int[size];
+ for (int i = 0; i < size; i++) {
+ deltaValues[i] = raf.readUnsignedShort();
+ }
+ }
+
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/DirectoryEntry.java b/src/typecast/net/java/dev/typecast/ot/table/DirectoryEntry.java
new file mode 100644
index 000000000..c0f2f9bc1
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/DirectoryEntry.java
@@ -0,0 +1,115 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: DirectoryEntry.java,v 1.2 2004-12-09 23:46:21 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class DirectoryEntry implements Cloneable {
+
+ private int _tag;
+ private int _checksum;
+ private int _offset;
+ private int _length;
+
+ protected DirectoryEntry(DataInput di) throws IOException {
+ _tag = di.readInt();
+ _checksum = di.readInt();
+ _offset = di.readInt();
+ _length = di.readInt();
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ return null;
+ }
+ }
+
+ public int getChecksum() {
+ return _checksum;
+ }
+
+ public int getLength() {
+ return _length;
+ }
+
+ public int getOffset() {
+ return _offset;
+ }
+
+ public int getTag() {
+ return _tag;
+ }
+
+ public String getTagAsString() {
+ return new StringBuffer()
+ .append((char)((_tag>>24)&0xff))
+ .append((char)((_tag>>16)&0xff))
+ .append((char)((_tag>>8)&0xff))
+ .append((char)((_tag)&0xff))
+ .toString();
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("'").append(getTagAsString())
+ .append("' - chksm = 0x").append(Integer.toHexString(_checksum))
+ .append(", off = 0x").append(Integer.toHexString(_offset))
+ .append(", len = ").append(_length)
+ .toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/DsigEntry.java b/src/typecast/net/java/dev/typecast/ot/table/DsigEntry.java
new file mode 100644
index 000000000..6ce41ec48
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/DsigEntry.java
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.DataInput;
+
+/**
+ *
+ * @version $Id: DsigEntry.java,v 1.1.1.1 2004-12-05 23:14:37 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class DsigEntry {
+
+ private int format;
+ private int length;
+ private int offset;
+
+ /** Creates new DsigEntry */
+ protected DsigEntry(DataInput di) throws IOException {
+ format = di.readInt();
+ length = di.readInt();
+ offset = di.readInt();
+ }
+
+ public int getFormat() {
+ return format;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/DsigTable.java b/src/typecast/net/java/dev/typecast/ot/table/DsigTable.java
new file mode 100644
index 000000000..8d63800d4
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/DsigTable.java
@@ -0,0 +1,69 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.DataInput;
+
+/**
+ *
+ * @version $Id: DsigTable.java,v 1.1.1.1 2004-12-05 23:14:37 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class DsigTable implements Table {
+
+ private DirectoryEntry de;
+ private int version;
+ private int numSigs;
+ private int flag;
+ private DsigEntry[] dsigEntry;
+ private SignatureBlock[] sigBlocks;
+
+ /** Creates new DsigTable */
+ protected DsigTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readInt();
+ numSigs = di.readUnsignedShort();
+ flag = di.readUnsignedShort();
+ dsigEntry = new DsigEntry[numSigs];
+ sigBlocks = new SignatureBlock[numSigs];
+ for (int i = 0; i < numSigs; i++) {
+ dsigEntry[i] = new DsigEntry(di);
+ }
+ for (int i = 0; i < numSigs; i++) {
+ sigBlocks[i] = new SignatureBlock(di);
+ }
+ }
+
+ /**
+ * Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return DSIG;
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer().append("DSIG\n");
+ for (int i = 0; i < numSigs; i++) {
+ sb.append(sigBlocks[i].toString());
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Feature.java b/src/typecast/net/java/dev/typecast/ot/table/Feature.java
new file mode 100644
index 000000000..34adf4662
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Feature.java
@@ -0,0 +1,85 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Feature.java,v 1.2 2007-01-24 09:47:46 davidsch Exp $
+ */
+public class Feature {
+
+ private int _featureParams;
+ private int _lookupCount;
+ private int[] _lookupListIndex;
+
+ /** Creates new Feature */
+ protected Feature(DataInput di) throws IOException {
+ _featureParams = di.readUnsignedShort();
+ _lookupCount = di.readUnsignedShort();
+ _lookupListIndex = new int[_lookupCount];
+ for (int i = 0; i < _lookupCount; i++) {
+ _lookupListIndex[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getLookupCount() {
+ return _lookupCount;
+ }
+
+ public int getLookupListIndex(int i) {
+ return _lookupListIndex[i];
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/FeatureList.java b/src/typecast/net/java/dev/typecast/ot/table/FeatureList.java
new file mode 100644
index 000000000..8f17c461f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/FeatureList.java
@@ -0,0 +1,118 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: FeatureList.java,v 1.3 2007-01-24 09:54:44 davidsch Exp $
+ */
+public class FeatureList {
+
+ private int _featureCount;
+ private FeatureRecord[] _featureRecords;
+ private Feature[] _features;
+
+ /** Creates new FeatureList */
+ public FeatureList(DataInputStream dis, int offset) throws IOException {
+
+ // Ensure we're in the right place
+ dis.reset();
+ dis.skipBytes(offset);
+
+ // Start reading
+ _featureCount = dis.readUnsignedShort();
+ _featureRecords = new FeatureRecord[_featureCount];
+ _features = new Feature[_featureCount];
+ for (int i = 0; i < _featureCount; i++) {
+ _featureRecords[i] = new FeatureRecord(dis);
+ }
+ for (int i = 0; i < _featureCount; i++) {
+ dis.reset();
+ dis.skipBytes(offset + _featureRecords[i].getOffset());
+ _features[i] = new Feature(dis);
+ }
+ }
+
+ public int getFeatureCount() {
+ return _featureCount;
+ }
+
+ public FeatureRecord getFeatureRecord(int i) {
+ return _featureRecords[i];
+ }
+
+ public Feature getFeature(int i) {
+ return _features[i];
+ }
+
+ public Feature findFeature(LangSys langSys, String tag) {
+ if (tag.length() != 4) {
+ return null;
+ }
+ int tagVal = ((tag.charAt(0)<<24)
+ | (tag.charAt(1)<<16)
+ | (tag.charAt(2)<<8)
+ | tag.charAt(3));
+ for (int i = 0; i < _featureCount; i++) {
+ if (_featureRecords[i].getTag() == tagVal) {
+ if (langSys.isFeatureIndexed(i)) {
+ return _features[i];
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/FeatureRecord.java b/src/typecast/net/java/dev/typecast/ot/table/FeatureRecord.java
new file mode 100644
index 000000000..7c2788892
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/FeatureRecord.java
@@ -0,0 +1,88 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: FeatureRecord.java,v 1.2 2007-01-24 09:47:48 davidsch Exp $
+ */
+public class FeatureRecord {
+
+ private int _tag;
+ private int _offset;
+
+ /** Creates new FeatureRecord */
+ protected FeatureRecord(DataInput di) throws IOException {
+ _tag = di.readInt();
+ _offset = di.readUnsignedShort();
+ }
+
+ public int getTag() {
+ return _tag;
+ }
+
+ public int getOffset() {
+ return _offset;
+ }
+
+ public String getTagAsString() {
+ return new StringBuffer()
+ .append((char)((_tag>>24)&0xff))
+ .append((char)((_tag>>16)&0xff))
+ .append((char)((_tag>>8)&0xff))
+ .append((char)((_tag)&0xff))
+ .toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/FeatureTags.java b/src/typecast/net/java/dev/typecast/ot/table/FeatureTags.java
new file mode 100644
index 000000000..8d573d0c6
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/FeatureTags.java
@@ -0,0 +1,63 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * Definition of Feature tags
+ *
+ * @version $Id: FeatureTags.java,v 1.2 2007-01-24 09:47:48 davidsch Exp $
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ */
+public interface FeatureTags {
+ public static final String FEATURE_TAG_INIT = "init";
+ public static final String FEATURE_TAG_MEDI = "medi";
+ public static final String FEATURE_TAG_FINA = "fina";
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/FpgmTable.java b/src/typecast/net/java/dev/typecast/ot/table/FpgmTable.java
new file mode 100644
index 000000000..37a2ae045
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/FpgmTable.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Disassembler;
+
+/**
+ * @version $Id: FpgmTable.java,v 1.1.1.1 2004-12-05 23:14:38 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class FpgmTable extends Program implements Table {
+
+ private DirectoryEntry de;
+
+ protected FpgmTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ readInstructions(di, de.getLength());
+ }
+
+ public int getType() {
+ return fpgm;
+ }
+
+ public String toString() {
+ return Disassembler.disassemble(getInstructions(), 0);
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GaspRange.java b/src/typecast/net/java/dev/typecast/ot/table/GaspRange.java
new file mode 100644
index 000000000..9f343e942
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GaspRange.java
@@ -0,0 +1,45 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: GaspRange.java,v 1.1.1.1 2004-12-05 23:14:38 davidsch Exp $
+ */
+public class GaspRange {
+
+ public static final int GASP_GRIDFIT = 1;
+ public static final int GASP_DOGRAY = 2;
+
+ private int rangeMaxPPEM;
+ private int rangeGaspBehavior;
+
+ /** Creates new GaspRange */
+ protected GaspRange(DataInput di) throws IOException {
+ rangeMaxPPEM = di.readUnsignedShort();
+ rangeGaspBehavior = di.readUnsignedShort();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(" rangeMaxPPEM: ").append(rangeMaxPPEM)
+ .append("\n rangeGaspBehavior: 0x").append(rangeGaspBehavior);
+ if ((rangeGaspBehavior & GASP_GRIDFIT) != 0) {
+ sb.append("- GASP_GRIDFIT ");
+ }
+ if ((rangeGaspBehavior & GASP_DOGRAY) != 0) {
+ sb.append("- GASP_DOGRAY");
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GaspTable.java b/src/typecast/net/java/dev/typecast/ot/table/GaspTable.java
new file mode 100644
index 000000000..50a1bcd93
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GaspTable.java
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: GaspTable.java,v 1.1.1.1 2004-12-05 23:14:39 davidsch Exp $
+ */
+public class GaspTable implements Table {
+
+ private DirectoryEntry de;
+ private int version;
+ private int numRanges;
+ private GaspRange[] gaspRange;
+
+ /** Creates new GaspTable */
+ protected GaspTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readUnsignedShort();
+ numRanges = di.readUnsignedShort();
+ gaspRange = new GaspRange[numRanges];
+ for (int i = 0; i < numRanges; i++) {
+ gaspRange[i] = new GaspRange(di);
+ }
+ }
+
+ public int getType() {
+ return gasp;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'gasp' Table - Grid-fitting And Scan-conversion Procedure\n---------------------------------------------------------");
+ sb.append("\n 'gasp' version: ").append(version);
+ sb.append("\n numRanges: ").append(numRanges);
+ for (int i = 0; i < numRanges; i++) {
+ sb.append("\n\n gasp Range ").append(i).append("\n");
+ sb.append(gaspRange[i].toString());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeComp.java b/src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeComp.java
new file mode 100644
index 000000000..0a3f91a2a
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeComp.java
@@ -0,0 +1,200 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: GlyfCompositeComp.java,v 1.3 2010-08-10 11:41:55 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class GlyfCompositeComp {
+
+ public static final short ARG_1_AND_2_ARE_WORDS = 0x0001;
+ public static final short ARGS_ARE_XY_VALUES = 0x0002;
+ public static final short ROUND_XY_TO_GRID = 0x0004;
+ public static final short WE_HAVE_A_SCALE = 0x0008;
+ public static final short MORE_COMPONENTS = 0x0020;
+ public static final short WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
+ public static final short WE_HAVE_A_TWO_BY_TWO = 0x0080;
+ public static final short WE_HAVE_INSTRUCTIONS = 0x0100;
+ public static final short USE_MY_METRICS = 0x0200;
+
+ private int _firstIndex;
+ private int _firstContour;
+ private short _argument1;
+ private short _argument2;
+ private int _flags;
+ private int _glyphIndex;
+ private double _xscale = 1.0;
+ private double _yscale = 1.0;
+ private double _scale01 = 0.0;
+ private double _scale10 = 0.0;
+ private int _xtranslate = 0;
+ private int _ytranslate = 0;
+ private int _point1 = 0;
+ private int _point2 = 0;
+
+ protected GlyfCompositeComp(int firstIndex, int firstContour, DataInput di)
+ throws IOException {
+ _firstIndex = firstIndex;
+ _firstContour = firstContour;
+ _flags = di.readUnsignedShort();
+ _glyphIndex = di.readUnsignedShort();
+
+ // Get the arguments as just their raw values
+ if ((_flags & ARG_1_AND_2_ARE_WORDS) != 0) {
+ _argument1 = di.readShort();
+ _argument2 = di.readShort();
+ } else {
+ _argument1 = (short) di.readByte();
+ _argument2 = (short) di.readByte();
+ }
+
+ // Assign the arguments according to the flags
+ if ((_flags & ARGS_ARE_XY_VALUES) != 0) {
+ _xtranslate = _argument1;
+ _ytranslate = _argument2;
+ } else {
+ _point1 = _argument1;
+ _point2 = _argument2;
+ }
+
+ // Get the scale values (if any)
+ if ((_flags & WE_HAVE_A_SCALE) != 0) {
+ int i = di.readShort();
+ _xscale = _yscale = (double) i / (double) 0x4000;
+ } else if ((_flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) {
+ short i = di.readShort();
+ _xscale = (double) i / (double) 0x4000;
+ i = di.readShort();
+ _yscale = (double) i / (double) 0x4000;
+ } else if ((_flags & WE_HAVE_A_TWO_BY_TWO) != 0) {
+ int i = di.readShort();
+ _xscale = (double) i / (double) 0x4000;
+ i = di.readShort();
+ _scale01 = (double) i / (double) 0x4000;
+ i = di.readShort();
+ _scale10 = (double) i / (double) 0x4000;
+ i = di.readShort();
+ _yscale = (double) i / (double) 0x4000;
+ }
+ }
+
+ public int getFirstIndex() {
+ return _firstIndex;
+ }
+
+ public int getFirstContour() {
+ return _firstContour;
+ }
+
+ public short getArgument1() {
+ return _argument1;
+ }
+
+ public short getArgument2() {
+ return _argument2;
+ }
+
+ public int getFlags() {
+ return _flags;
+ }
+
+ public int getGlyphIndex() {
+ return _glyphIndex;
+ }
+
+ public double getScale01() {
+ return _scale01;
+ }
+
+ public double getScale10() {
+ return _scale10;
+ }
+
+ public double getXScale() {
+ return _xscale;
+ }
+
+ public double getYScale() {
+ return _yscale;
+ }
+
+ public int getXTranslate() {
+ return _xtranslate;
+ }
+
+ public int getYTranslate() {
+ return _ytranslate;
+ }
+
+ /**
+ * Transforms an x-coordinate of a point for this component.
+ * @param x The x-coordinate of the point to transform
+ * @param y The y-coordinate of the point to transform
+ * @return The transformed x-coordinate
+ */
+ public int scaleX(int x, int y) {
+ return (int)((double) x * _xscale + (double) y * _scale10);
+ }
+
+ /**
+ * Transforms a y-coordinate of a point for this component.
+ * @param x The x-coordinate of the point to transform
+ * @param y The y-coordinate of the point to transform
+ * @return The transformed y-coordinate
+ */
+ public int scaleY(int x, int y) {
+ return (int)((double) x * _scale01 + (double) y * _yscale);
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeDescript.java b/src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeDescript.java
new file mode 100644
index 000000000..97c0b0f79
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GlyfCompositeDescript.java
@@ -0,0 +1,202 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import java.util.ArrayList;
+
+/**
+ * Glyph description for composite glyphs. Composite glyphs are made up of one
+ * or more simple glyphs, usually with some sort of transformation applied to
+ * each.
+ *
+ * @version $Id: GlyfCompositeDescript.java,v 1.5 2007-01-25 08:43:18 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class GlyfCompositeDescript extends GlyfDescript {
+
+ private ArrayList<GlyfCompositeComp> _components =
+ new ArrayList<GlyfCompositeComp>();
+
+ public GlyfCompositeDescript(
+ GlyfTable parentTable,
+ int glyphIndex,
+ DataInput di) throws IOException {
+ super(parentTable, glyphIndex, (short) -1, di);
+
+ // Get all of the composite components
+ GlyfCompositeComp comp;
+ int firstIndex = 0;
+ int firstContour = 0;
+ try {
+ do {
+ _components.add(comp = new GlyfCompositeComp(firstIndex, firstContour, di));
+ GlyfDescript desc = parentTable.getDescription(comp.getGlyphIndex());
+ if (desc != null) {
+ firstIndex += desc.getPointCount();
+ firstContour += desc.getContourCount();
+ }
+ } while ((comp.getFlags() & GlyfCompositeComp.MORE_COMPONENTS) != 0);
+
+ // Are there hinting intructions to read?
+ if ((comp.getFlags() & GlyfCompositeComp.WE_HAVE_INSTRUCTIONS) != 0) {
+ readInstructions(di, di.readShort());
+ }
+ } catch (IOException e) {
+ throw e;
+// } catch (Exception e) {
+// int foo = 0;
+ }
+ }
+
+ public int getEndPtOfContours(int i) {
+ GlyfCompositeComp c = getCompositeCompEndPt(i);
+ if (c != null) {
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ return gd.getEndPtOfContours(i - c.getFirstContour()) + c.getFirstIndex();
+ }
+ return 0;
+ }
+
+ public byte getFlags(int i) {
+ GlyfCompositeComp c = getCompositeComp(i);
+ if (c != null) {
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ return gd.getFlags(i - c.getFirstIndex());
+ }
+ return 0;
+ }
+
+ public short getXCoordinate(int i) {
+ GlyfCompositeComp c = getCompositeComp(i);
+ if (c != null) {
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ int n = i - c.getFirstIndex();
+ int x = gd.getXCoordinate(n);
+ int y = gd.getYCoordinate(n);
+ short x1 = (short) c.scaleX(x, y);
+ x1 += c.getXTranslate();
+ return x1;
+ }
+ return 0;
+ }
+
+ public short getYCoordinate(int i) {
+ GlyfCompositeComp c = getCompositeComp(i);
+ if (c != null) {
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ int n = i - c.getFirstIndex();
+ int x = gd.getXCoordinate(n);
+ int y = gd.getYCoordinate(n);
+ short y1 = (short) c.scaleY(x, y);
+ y1 += c.getYTranslate();
+ return y1;
+ }
+ return 0;
+ }
+
+ public boolean isComposite() {
+ return true;
+ }
+
+ public int getPointCount() {
+ GlyfCompositeComp c = _components.get(_components.size()-1);
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ if (gd != null) {
+ return c.getFirstIndex() + gd.getPointCount();
+ } else {
+ return 0;
+ }
+ }
+
+ public int getContourCount() {
+ GlyfCompositeComp c = _components.get(_components.size()-1);
+ return c.getFirstContour() + _parentTable.getDescription(c.getGlyphIndex()).getContourCount();
+ }
+
+ public int getComponentIndex(int i) {
+ return _components.get(i).getFirstIndex();
+ }
+
+ public int getComponentCount() {
+ return _components.size();
+ }
+
+ public GlyfCompositeComp getComponent(int i) {
+ return _components.get(i);
+ }
+
+ protected GlyfCompositeComp getCompositeComp(int i) {
+ GlyfCompositeComp c;
+ for (int n = 0; n < _components.size(); n++) {
+ c = _components.get(n);
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ if (c.getFirstIndex() <= i && i < (c.getFirstIndex() + gd.getPointCount())) {
+ return c;
+ }
+ }
+ return null;
+ }
+
+ protected GlyfCompositeComp getCompositeCompEndPt(int i) {
+ GlyfCompositeComp c;
+ for (int j = 0; j < _components.size(); j++) {
+ c = _components.get(j);
+ GlyphDescription gd = _parentTable.getDescription(c.getGlyphIndex());
+ if (c.getFirstContour() <= i && i < (c.getFirstContour() + gd.getContourCount())) {
+ return c;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GlyfDescript.java b/src/typecast/net/java/dev/typecast/ot/table/GlyfDescript.java
new file mode 100644
index 000000000..49ae5b494
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GlyfDescript.java
@@ -0,0 +1,124 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: GlyfDescript.java,v 1.3 2007-01-24 09:47:48 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public abstract class GlyfDescript extends Program implements GlyphDescription {
+
+ // flags
+ public static final byte onCurve = 0x01;
+ public static final byte xShortVector = 0x02;
+ public static final byte yShortVector = 0x04;
+ public static final byte repeat = 0x08;
+ public static final byte xDual = 0x10;
+ public static final byte yDual = 0x20;
+
+ protected GlyfTable _parentTable;
+ private int _glyphIndex;
+ private int _numberOfContours;
+ private short _xMin;
+ private short _yMin;
+ private short _xMax;
+ private short _yMax;
+
+ protected GlyfDescript(
+ GlyfTable parentTable,
+ int glyphIndex,
+ short numberOfContours,
+ DataInput di) throws IOException {
+ _parentTable = parentTable;
+ _numberOfContours = numberOfContours;
+ _xMin = di.readShort();
+ _yMin = di.readShort();
+ _xMax = di.readShort();
+ _yMax = di.readShort();
+ }
+
+ public int getNumberOfContours() {
+ return _numberOfContours;
+ }
+
+ public int getGlyphIndex() {
+ return _glyphIndex;
+ }
+
+ public short getXMaximum() {
+ return _xMax;
+ }
+
+ public short getXMinimum() {
+ return _xMin;
+ }
+
+ public short getYMaximum() {
+ return _yMax;
+ }
+
+ public short getYMinimum() {
+ return _yMin;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append(" numberOfContours: ").append(_numberOfContours)
+ .append("\n xMin: ").append(_xMin)
+ .append("\n yMin: ").append(_yMin)
+ .append("\n xMax: ").append(_xMax)
+ .append("\n yMax: ").append(_yMax)
+ .toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GlyfSimpleDescript.java b/src/typecast/net/java/dev/typecast/ot/table/GlyfSimpleDescript.java
new file mode 100644
index 000000000..e2c3a2c84
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GlyfSimpleDescript.java
@@ -0,0 +1,245 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Disassembler;
+
+/**
+ * @version $Id: GlyfSimpleDescript.java,v 1.3 2007-01-24 09:47:47 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class GlyfSimpleDescript extends GlyfDescript {
+
+ private int[] _endPtsOfContours;
+ private byte[] _flags;
+ private short[] _xCoordinates;
+ private short[] _yCoordinates;
+ private int _count;
+
+ public GlyfSimpleDescript(
+ GlyfTable parentTable,
+ int glyphIndex,
+ short numberOfContours,
+ DataInput di) throws IOException {
+ super(parentTable, glyphIndex, numberOfContours, di);
+
+ // Simple glyph description
+ _endPtsOfContours = new int[numberOfContours];
+ for (int i = 0; i < numberOfContours; i++) {
+ _endPtsOfContours[i] = di.readShort();
+ }
+
+ // The last end point index reveals the total number of points
+ _count = _endPtsOfContours[numberOfContours-1] + 1;
+ _flags = new byte[_count];
+ _xCoordinates = new short[_count];
+ _yCoordinates = new short[_count];
+
+ int instructionCount = di.readShort();
+ readInstructions(di, instructionCount);
+ readFlags(_count, di);
+ readCoords(_count, di);
+ }
+
+ public int getEndPtOfContours(int i) {
+ return _endPtsOfContours[i];
+ }
+
+ public byte getFlags(int i) {
+ return _flags[i];
+ }
+
+ public short getXCoordinate(int i) {
+ return _xCoordinates[i];
+ }
+
+ public short getYCoordinate(int i) {
+ return _yCoordinates[i];
+ }
+
+ public boolean isComposite() {
+ return false;
+ }
+
+ public int getPointCount() {
+ return _count;
+ }
+
+ public int getContourCount() {
+ return getNumberOfContours();
+ }
+ /*
+ public int getComponentIndex(int c) {
+ return 0;
+ }
+
+ public int getComponentCount() {
+ return 1;
+ }
+ */
+ /**
+ * The table is stored as relative values, but we'll store them as absolutes
+ */
+ private void readCoords(int count, DataInput di) throws IOException {
+ short x = 0;
+ short y = 0;
+ for (int i = 0; i < count; i++) {
+ if ((_flags[i] & xDual) != 0) {
+ if ((_flags[i] & xShortVector) != 0) {
+ x += (short) di.readUnsignedByte();
+ }
+ } else {
+ if ((_flags[i] & xShortVector) != 0) {
+ x += (short) -((short) di.readUnsignedByte());
+ } else {
+ x += di.readShort();
+ }
+ }
+ _xCoordinates[i] = x;
+ }
+
+ for (int i = 0; i < count; i++) {
+ if ((_flags[i] & yDual) != 0) {
+ if ((_flags[i] & yShortVector) != 0) {
+ y += (short) di.readUnsignedByte();
+ }
+ } else {
+ if ((_flags[i] & yShortVector) != 0) {
+ y += (short) -((short) di.readUnsignedByte());
+ } else {
+ y += di.readShort();
+ }
+ }
+ _yCoordinates[i] = y;
+ }
+ }
+
+ /**
+ * The flags are run-length encoded
+ */
+ private void readFlags(int flagCount, DataInput di) throws IOException {
+ try {
+ for (int index = 0; index < flagCount; index++) {
+ _flags[index] = di.readByte();
+ if ((_flags[index] & repeat) != 0) {
+ int repeats = di.readByte();
+ for (int i = 1; i <= repeats; i++) {
+ _flags[index + i] = _flags[index];
+ }
+ index += repeats;
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println("error: array index out of bounds");
+ }
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(super.toString());
+ sb.append("\n\n EndPoints\n ---------");
+ for (int i = 0; i < _endPtsOfContours.length; i++) {
+ sb.append("\n ").append(i).append(": ").append(_endPtsOfContours[i]);
+ }
+ sb.append("\n\n Length of Instructions: ");
+ sb.append(getInstructions().length).append("\n");
+ sb.append(Disassembler.disassemble(getInstructions(), 8));
+ sb.append("\n Flags\n -----");
+ for (int i = 0; i < _flags.length; i++) {
+ sb.append("\n ").append(i).append(": ");
+ if ((_flags[i] & 0x20) != 0) {
+ sb.append("YDual ");
+ } else {
+ sb.append(" ");
+ }
+ if ((_flags[i] & 0x10) != 0) {
+ sb.append("XDual ");
+ } else {
+ sb.append(" ");
+ }
+ if ((_flags[i] & 0x08) != 0) {
+ sb.append("Repeat ");
+ } else {
+ sb.append(" ");
+ }
+ if ((_flags[i] & 0x04) != 0) {
+ sb.append("Y-Short ");
+ } else {
+ sb.append(" ");
+ }
+ if ((_flags[i] & 0x02) != 0) {
+ sb.append("X-Short ");
+ } else {
+ sb.append(" ");
+ }
+ if ((_flags[i] & 0x01) != 0) {
+ sb.append("On");
+ } else {
+ sb.append(" ");
+ }
+ }
+ sb.append("\n\n Coordinates\n -----------");
+ short oldX = 0;
+ short oldY = 0;
+ for (int i = 0; i < _xCoordinates.length; i++) {
+ sb.append("\n ").append(i)
+ .append(": Rel (").append(_xCoordinates[i] - oldX)
+ .append(", ").append(_yCoordinates[i] - oldY)
+ .append(") -> Abs (").append(_xCoordinates[i])
+ .append(", ").append(_yCoordinates[i]).append(")");
+ oldX = _xCoordinates[i];
+ oldY = _yCoordinates[i];
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GlyfTable.java b/src/typecast/net/java/dev/typecast/ot/table/GlyfTable.java
new file mode 100644
index 000000000..03f519db2
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GlyfTable.java
@@ -0,0 +1,132 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * @version $Id: GlyfTable.java,v 1.6 2010-08-10 11:46:30 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class GlyfTable implements Table {
+
+ private DirectoryEntry _de;
+ private GlyfDescript[] _descript;
+
+ protected GlyfTable(
+ DirectoryEntry de,
+ DataInput di,
+ MaxpTable maxp,
+ LocaTable loca) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _descript = new GlyfDescript[maxp.getNumGlyphs()];
+
+ // Buffer the whole table so we can randomly access it
+ byte[] buf = new byte[de.getLength()];
+ di.readFully(buf);
+ ByteArrayInputStream bais = new ByteArrayInputStream(buf);
+
+ // Process all the simple glyphs
+ for (int i = 0; i < maxp.getNumGlyphs(); i++) {
+ int len = loca.getOffset(i + 1) - loca.getOffset(i);
+ if (len > 0) {
+ bais.reset();
+ bais.skip(loca.getOffset(i));
+ DataInputStream dis = new DataInputStream(bais);
+ short numberOfContours = dis.readShort();
+ if (numberOfContours >= 0) {
+ _descript[i] = new GlyfSimpleDescript(this, i, numberOfContours, dis);
+ }
+ } else {
+ _descript[i] = null;
+ }
+ }
+
+ // Now do all the composite glyphs
+ for (int i = 0; i < maxp.getNumGlyphs(); i++) {
+ int len = loca.getOffset(i + 1) - loca.getOffset(i);
+ if (len > 0) {
+ bais.reset();
+ bais.skip(loca.getOffset(i));
+ DataInputStream dis = new DataInputStream(bais);
+ short numberOfContours = dis.readShort();
+ if (numberOfContours < 0) {
+ _descript[i] = new GlyfCompositeDescript(this, i, dis);
+ }
+ }
+ }
+ }
+
+ public GlyfDescript getDescription(int i) {
+ if (i < _descript.length) {
+ return _descript[i];
+ } else {
+ return null;
+ }
+ }
+
+ public int getType() {
+ return glyf;
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GlyphDescription.java b/src/typecast/net/java/dev/typecast/ot/table/GlyphDescription.java
new file mode 100644
index 000000000..b23f31364
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GlyphDescription.java
@@ -0,0 +1,86 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * Specifies access to glyph description classes, simple and composite.
+ * @version $Id: GlyphDescription.java,v 1.3 2007-01-24 09:47:45 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public interface GlyphDescription {
+
+ public int getGlyphIndex();
+
+ public int getEndPtOfContours(int i);
+
+ public byte getFlags(int i);
+
+ public short getXCoordinate(int i);
+
+ public short getYCoordinate(int i);
+
+ public short getXMaximum();
+
+ public short getXMinimum();
+
+ public short getYMaximum();
+
+ public short getYMinimum();
+
+ public boolean isComposite();
+
+ public int getPointCount();
+
+ public int getContourCount();
+
+ // public int getComponentIndex(int c);
+ // public int getComponentCount();
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GposTable.java b/src/typecast/net/java/dev/typecast/ot/table/GposTable.java
new file mode 100644
index 000000000..3efeeaa03
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GposTable.java
@@ -0,0 +1,66 @@
+/*
+ * $Id: GposTable.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * TODO: To be implemented
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: GposTable.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class GposTable implements Table {
+
+ private DirectoryEntry _de;
+
+ protected GposTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+
+ // GPOS Header
+ int version = di.readInt();
+ int scriptList = di.readInt();
+ int featureList = di.readInt();
+ int lookupList = di.readInt();
+ }
+
+ /** Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return GPOS;
+ }
+
+ public String toString() {
+ return "GPOS";
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/GsubTable.java b/src/typecast/net/java/dev/typecast/ot/table/GsubTable.java
new file mode 100644
index 000000000..d7f9c355f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/GsubTable.java
@@ -0,0 +1,181 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: GsubTable.java,v 1.3 2007-01-24 09:47:46 davidsch Exp $
+ */
+public class GsubTable implements Table, LookupSubtableFactory {
+
+ private DirectoryEntry _de;
+ private ScriptList _scriptList;
+ private FeatureList _featureList;
+ private LookupList _lookupList;
+
+ protected GsubTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+
+ // Load into a temporary buffer, and create another input stream
+ byte[] buf = new byte[de.getLength()];
+ di.readFully(buf);
+ DataInputStream dis = new DataInputStream(new ByteArrayInputStream(buf));
+
+ // GSUB Header
+ int version = dis.readInt();
+ int scriptListOffset = dis.readUnsignedShort();
+ int featureListOffset = dis.readUnsignedShort();
+ int lookupListOffset = dis.readUnsignedShort();
+
+ // Script List
+ _scriptList = new ScriptList(dis, scriptListOffset);
+
+ // Feature List
+ _featureList = new FeatureList(dis, featureListOffset);
+
+ // Lookup List
+ _lookupList = new LookupList(dis, lookupListOffset, this);
+ }
+
+ /**
+ * 1 - Single - Replace one glyph with one glyph
+ * 2 - Multiple - Replace one glyph with more than one glyph
+ * 3 - Alternate - Replace one glyph with one of many glyphs
+ * 4 - Ligature - Replace multiple glyphs with one glyph
+ * 5 - Context - Replace one or more glyphs in context
+ * 6 - Chaining - Context Replace one or more glyphs in chained context
+ */
+ public LookupSubtable read(
+ int type,
+ DataInputStream dis,
+ int offset) throws IOException {
+ LookupSubtable s = null;
+ switch (type) {
+ case 1:
+ s = SingleSubst.read(dis, offset);
+ break;
+ case 2:
+// s = MultipleSubst.read(dis, offset);
+ break;
+ case 3:
+// s = AlternateSubst.read(dis, offset);
+ break;
+ case 4:
+ s = LigatureSubst.read(dis, offset);
+ break;
+ case 5:
+// s = ContextSubst.read(dis, offset);
+ break;
+ case 6:
+// s = ChainingSubst.read(dis, offset);
+ break;
+ }
+ return s;
+ }
+
+ /** Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return GSUB;
+ }
+
+ public ScriptList getScriptList() {
+ return _scriptList;
+ }
+
+ public FeatureList getFeatureList() {
+ return _featureList;
+ }
+
+ public LookupList getLookupList() {
+ return _lookupList;
+ }
+
+ public String toString() {
+ return "GSUB";
+ }
+
+ public static String lookupTypeAsString(int type) {
+ switch (type) {
+ case 1:
+ return "Single";
+ case 2:
+ return "Multiple";
+ case 3:
+ return "Alternate";
+ case 4:
+ return "Ligature";
+ case 5:
+ return "Context";
+ case 6:
+ return "Chaining";
+ }
+ return "Unknown";
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/HdmxTable.java b/src/typecast/net/java/dev/typecast/ot/table/HdmxTable.java
new file mode 100644
index 000000000..68a03c590
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/HdmxTable.java
@@ -0,0 +1,130 @@
+/*
+ * $Id: HdmxTable.java,v 1.2 2007-07-26 11:12:30 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * The Horizontal Device Metrics table for TrueType outlines. This stores
+ * integer advance widths scaled to specific pixel sizes.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: HdmxTable.java,v 1.2 2007-07-26 11:12:30 davidsch Exp $
+ */
+public class HdmxTable implements Table {
+
+ public class DeviceRecord {
+
+ private short _pixelSize;
+ private short _maxWidth;
+ private short[] _widths;
+
+ protected DeviceRecord(int numGlyphs, DataInput di) throws IOException {
+ _pixelSize = di.readByte();
+ _maxWidth = di.readByte();
+ _widths = new short[numGlyphs];
+ for (int i = 0; i < numGlyphs; ++i) {
+ _widths[i] = di.readByte();
+ }
+ }
+
+ public short getPixelSize() {
+ return _pixelSize;
+ }
+
+ public short getMaxWidth() {
+ return _maxWidth;
+ }
+
+ public short[] getWidths() {
+ return _widths;
+ }
+
+ public short getWidth(int glyphidx) {
+ return _widths[glyphidx];
+ }
+
+ }
+
+ private DirectoryEntry _de;
+ private int _version;
+ private short _numRecords;
+ private int _sizeDeviceRecords;
+ private DeviceRecord[] _records;
+
+ /** Creates a new instance of HdmxTable */
+ protected HdmxTable(DirectoryEntry de, DataInput di, MaxpTable maxp)
+ throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _version = di.readUnsignedShort();
+ _numRecords = di.readShort();
+ _sizeDeviceRecords = di.readInt();
+ _records = new DeviceRecord[_numRecords];
+
+ // Read the device records
+ for (int i = 0; i < _numRecords; ++i) {
+ _records[i] = new DeviceRecord(maxp.getNumGlyphs(), di);
+ }
+ }
+
+ public int getNumberOfRecords() {
+ return _numRecords;
+ }
+
+ public DeviceRecord getRecord(int i) {
+ return _records[i];
+ }
+
+ public int getType() {
+ return hdmx;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'hdmx' Table - Horizontal Device Metrics\n----------------------------------------\n");
+ sb.append("Size = ").append(_de.getLength()).append(" bytes\n")
+ .append("\t'hdmx' version: ").append(_version).append("\n")
+ .append("\t# device records: ").append(_numRecords).append("\n")
+ .append("\tRecord length: ").append(_sizeDeviceRecords).append("\n");
+ for (int i = 0; i < _numRecords; ++i) {
+ sb.append("\tDevRec ").append(i)
+ .append(": ppem = ").append(_records[i].getPixelSize())
+ .append(", maxWid = ").append(_records[i].getMaxWidth())
+ .append("\n");
+ for (int j = 0; j < _records[i].getWidths().length; ++j) {
+ sb.append(" ").append(j).append(". ")
+ .append(_records[i].getWidths()[j]).append("\n");
+ }
+ sb.append("\n\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/HeadTable.java b/src/typecast/net/java/dev/typecast/ot/table/HeadTable.java
new file mode 100644
index 000000000..c99ae768d
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/HeadTable.java
@@ -0,0 +1,205 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import net.java.dev.typecast.ot.Fixed;
+
+/**
+ * @version $Id: HeadTable.java,v 1.2 2004-12-21 10:23:20 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class HeadTable implements Table {
+
+ private DirectoryEntry _de;
+ private int _versionNumber;
+ private int _fontRevision;
+ private int _checkSumAdjustment;
+ private int _magicNumber;
+ private short _flags;
+ private short _unitsPerEm;
+ private long _created;
+ private long _modified;
+ private short _xMin;
+ private short _yMin;
+ private short _xMax;
+ private short _yMax;
+ private short _macStyle;
+ private short _lowestRecPPEM;
+ private short _fontDirectionHint;
+ private short _indexToLocFormat;
+ private short _glyphDataFormat;
+
+ protected HeadTable(DirectoryEntry de, DataInput di) throws IOException {
+ this._de = (DirectoryEntry) de.clone();
+ _versionNumber = di.readInt();
+ _fontRevision = di.readInt();
+ _checkSumAdjustment = di.readInt();
+ _magicNumber = di.readInt();
+ _flags = di.readShort();
+ _unitsPerEm = di.readShort();
+ _created = di.readLong();
+ _modified = di.readLong();
+ _xMin = di.readShort();
+ _yMin = di.readShort();
+ _xMax = di.readShort();
+ _yMax = di.readShort();
+ _macStyle = di.readShort();
+ _lowestRecPPEM = di.readShort();
+ _fontDirectionHint = di.readShort();
+ _indexToLocFormat = di.readShort();
+ _glyphDataFormat = di.readShort();
+ }
+
+ public int getCheckSumAdjustment() {
+ return _checkSumAdjustment;
+ }
+
+ public long getCreated() {
+ return _created;
+ }
+
+ public short getFlags() {
+ return _flags;
+ }
+
+ public short getFontDirectionHint() {
+ return _fontDirectionHint;
+ }
+
+ public int getFontRevision(){
+ return _fontRevision;
+ }
+
+ public short getGlyphDataFormat() {
+ return _glyphDataFormat;
+ }
+
+ public short getIndexToLocFormat() {
+ return _indexToLocFormat;
+ }
+
+ public short getLowestRecPPEM() {
+ return _lowestRecPPEM;
+ }
+
+ public short getMacStyle() {
+ return _macStyle;
+ }
+
+ public long getModified() {
+ return _modified;
+ }
+
+ public int getType() {
+ return head;
+ }
+
+ public short getUnitsPerEm() {
+ return _unitsPerEm;
+ }
+
+ public int getVersionNumber() {
+ return _versionNumber;
+ }
+
+ public short getXMax() {
+ return _xMax;
+ }
+
+ public short getXMin() {
+ return _xMin;
+ }
+
+ public short getYMax() {
+ return _yMax;
+ }
+
+ public short getYMin() {
+ return _yMin;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("'head' Table - Font Header\n--------------------------")
+ .append("\n 'head' version: ").append(Fixed.floatValue(_versionNumber))
+ .append("\n fontRevision: ").append(Fixed.roundedFloatValue(_fontRevision, 8))
+ .append("\n checkSumAdjustment: 0x").append(Integer.toHexString(_checkSumAdjustment).toUpperCase())
+ .append("\n magicNumber: 0x").append(Integer.toHexString(_magicNumber).toUpperCase())
+ .append("\n flags: 0x").append(Integer.toHexString(_flags).toUpperCase())
+ .append("\n unitsPerEm: ").append(_unitsPerEm)
+ .append("\n created: ").append(_created)
+ .append("\n modified: ").append(_modified)
+ .append("\n xMin: ").append(_xMin)
+ .append("\n yMin: ").append(_yMin)
+ .append("\n xMax: ").append(_xMax)
+ .append("\n yMax: ").append(_yMax)
+ .append("\n macStyle bits: ").append(Integer.toHexString(_macStyle).toUpperCase())
+ .append("\n lowestRecPPEM: ").append(_lowestRecPPEM)
+ .append("\n fontDirectionHint: ").append(_fontDirectionHint)
+ .append("\n indexToLocFormat: ").append(_indexToLocFormat)
+ .append("\n glyphDataFormat: ").append(_glyphDataFormat)
+ .toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/HheaTable.java b/src/typecast/net/java/dev/typecast/ot/table/HheaTable.java
new file mode 100644
index 000000000..4b49f41be
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/HheaTable.java
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Fixed;
+
+/**
+ * @version $Id: HheaTable.java,v 1.2 2010-08-10 11:44:02 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class HheaTable implements Table {
+
+ private DirectoryEntry de;
+ private int version;
+ private short ascender;
+ private short descender;
+ private short lineGap;
+ private short advanceWidthMax;
+ private short minLeftSideBearing;
+ private short minRightSideBearing;
+ private short xMaxExtent;
+ private short caretSlopeRise;
+ private short caretSlopeRun;
+ private short metricDataFormat;
+ private int numberOfHMetrics;
+
+ protected HheaTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readInt();
+ ascender = di.readShort();
+ descender = di.readShort();
+ lineGap = di.readShort();
+ advanceWidthMax = di.readShort();
+ minLeftSideBearing = di.readShort();
+ minRightSideBearing = di.readShort();
+ xMaxExtent = di.readShort();
+ caretSlopeRise = di.readShort();
+ caretSlopeRun = di.readShort();
+ for (int i = 0; i < 5; i++) {
+ di.readShort();
+ }
+ metricDataFormat = di.readShort();
+ numberOfHMetrics = di.readUnsignedShort();
+ }
+
+ public short getAdvanceWidthMax() {
+ return advanceWidthMax;
+ }
+
+ public short getAscender() {
+ return ascender;
+ }
+
+ public short getCaretSlopeRise() {
+ return caretSlopeRise;
+ }
+
+ public short getCaretSlopeRun() {
+ return caretSlopeRun;
+ }
+
+ public short getDescender() {
+ return descender;
+ }
+
+ public short getLineGap() {
+ return lineGap;
+ }
+
+ public short getMetricDataFormat() {
+ return metricDataFormat;
+ }
+
+ public short getMinLeftSideBearing() {
+ return minLeftSideBearing;
+ }
+
+ public short getMinRightSideBearing() {
+ return minRightSideBearing;
+ }
+
+ public int getNumberOfHMetrics() {
+ return numberOfHMetrics;
+ }
+
+ public int getType() {
+ return hhea;
+ }
+
+ public short getXMaxExtent() {
+ return xMaxExtent;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("'hhea' Table - Horizontal Header\n--------------------------------")
+ .append("\n 'hhea' version: ").append(Fixed.floatValue(version))
+ .append("\n yAscender: ").append(ascender)
+ .append("\n yDescender: ").append(descender)
+ .append("\n yLineGap: ").append(lineGap)
+ .append("\n advanceWidthMax: ").append(advanceWidthMax)
+ .append("\n minLeftSideBearing: ").append(minLeftSideBearing)
+ .append("\n minRightSideBearing: ").append(minRightSideBearing)
+ .append("\n xMaxExtent: ").append(xMaxExtent)
+ .append("\n horizCaretSlopeNum: ").append(caretSlopeRise)
+ .append("\n horizCaretSlopeDenom: ").append(caretSlopeRun)
+ .append("\n reserved0: 0")
+ .append("\n reserved1: 0")
+ .append("\n reserved2: 0")
+ .append("\n reserved3: 0")
+ .append("\n reserved4: 0")
+ .append("\n metricDataFormat: ").append(metricDataFormat)
+ .append("\n numOf_LongHorMetrics: ").append(numberOfHMetrics)
+ .toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/HmtxTable.java b/src/typecast/net/java/dev/typecast/ot/table/HmtxTable.java
new file mode 100644
index 000000000..7b4cbae40
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/HmtxTable.java
@@ -0,0 +1,141 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: HmtxTable.java,v 1.5 2007-07-26 11:11:48 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class HmtxTable implements Table {
+
+ private DirectoryEntry _de;
+ private int[] _hMetrics = null;
+ private short[] _leftSideBearing = null;
+
+ protected HmtxTable(
+ DirectoryEntry de,
+ DataInput di,
+ HheaTable hhea,
+ MaxpTable maxp) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _hMetrics = new int[hhea.getNumberOfHMetrics()];
+ for (int i = 0; i < hhea.getNumberOfHMetrics(); ++i) {
+ _hMetrics[i] =
+ di.readUnsignedByte()<<24
+ | di.readUnsignedByte()<<16
+ | di.readUnsignedByte()<<8
+ | di.readUnsignedByte();
+ }
+ int lsbCount = maxp.getNumGlyphs() - hhea.getNumberOfHMetrics();
+ _leftSideBearing = new short[lsbCount];
+ for (int i = 0; i < lsbCount; ++i) {
+ _leftSideBearing[i] = di.readShort();
+ }
+ }
+
+ public int getAdvanceWidth(int i) {
+ if (_hMetrics == null) {
+ return 0;
+ }
+ if (i < _hMetrics.length) {
+ return _hMetrics[i] >> 16;
+ } else {
+ return _hMetrics[_hMetrics.length - 1] >> 16;
+ }
+ }
+
+ public short getLeftSideBearing(int i) {
+ if (_hMetrics == null) {
+ return 0;
+ }
+ if (i < _hMetrics.length) {
+ return (short)(_hMetrics[i] & 0xffff);
+ } else {
+ return _leftSideBearing[i - _hMetrics.length];
+ }
+ }
+
+ public int getType() {
+ return hmtx;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'hmtx' Table - Horizontal Metrics\n---------------------------------\n");
+ sb.append("Size = ").append(_de.getLength()).append(" bytes, ")
+ .append(_hMetrics.length).append(" entries\n");
+ for (int i = 0; i < _hMetrics.length; i++) {
+ sb.append(" ").append(i)
+ .append(". advWid: ").append(getAdvanceWidth(i))
+ .append(", LSdBear: ").append(getLeftSideBearing(i))
+ .append("\n");
+ }
+ for (int i = 0; i < _leftSideBearing.length; i++) {
+ sb.append(" LSdBear ").append(i + _hMetrics.length)
+ .append(": ").append(_leftSideBearing[i])
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ID.java b/src/typecast/net/java/dev/typecast/ot/table/ID.java
new file mode 100644
index 000000000..5dc79d766
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ID.java
@@ -0,0 +1,399 @@
+/*
+ * $Id: ID.java,v 1.1.1.1 2004-12-05 23:14:47 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ID.java,v 1.1.1.1 2004-12-05 23:14:47 davidsch Exp $
+ */
+public abstract class ID {
+
+ // Platform IDs
+ public static final short platformUnicode = 0;
+ public static final short platformMacintosh = 1;
+ public static final short platformISO = 2;
+ public static final short platformMicrosoft = 3;
+
+ // Unicode Encoding IDs
+ public static final short encodingUnicode10Semantics = 0;
+ public static final short encodingUnicode11Semantics = 1;
+ public static final short encodingISO10646Semantics = 2;
+ public static final short encodingUnicode20Semantics = 3;
+
+ // Microsoft Encoding IDs
+// public static final short encodingUndefined = 0;
+// public static final short encodingUGL = 1;
+ public static final short encodingSymbol = 0;
+ public static final short encodingUnicode = 1;
+ public static final short encodingShiftJIS = 2;
+ public static final short encodingPRC = 3;
+ public static final short encodingBig5 = 4;
+ public static final short encodingWansung = 5;
+ public static final short encodingJohab = 6;
+ public static final short encodingUCS4 = 10;
+
+ // Macintosh Encoding IDs
+ public static final short encodingRoman = 0;
+ public static final short encodingJapanese = 1;
+ public static final short encodingChinese = 2;
+ public static final short encodingKorean = 3;
+ public static final short encodingArabic = 4;
+ public static final short encodingHebrew = 5;
+ public static final short encodingGreek = 6;
+ public static final short encodingRussian = 7;
+ public static final short encodingRSymbol = 8;
+ public static final short encodingDevanagari = 9;
+ public static final short encodingGurmukhi = 10;
+ public static final short encodingGujarati = 11;
+ public static final short encodingOriya = 12;
+ public static final short encodingBengali = 13;
+ public static final short encodingTamil = 14;
+ public static final short encodingTelugu = 15;
+ public static final short encodingKannada = 16;
+ public static final short encodingMalayalam = 17;
+ public static final short encodingSinhalese = 18;
+ public static final short encodingBurmese = 19;
+ public static final short encodingKhmer = 20;
+ public static final short encodingThai = 21;
+ public static final short encodingLaotian = 22;
+ public static final short encodingGeorgian = 23;
+ public static final short encodingArmenian = 24;
+ public static final short encodingMaldivian = 25;
+ public static final short encodingTibetan = 26;
+ public static final short encodingMongolian = 27;
+ public static final short encodingGeez = 28;
+ public static final short encodingSlavic = 29;
+ public static final short encodingVietnamese = 30;
+ public static final short encodingSindhi = 31;
+ public static final short encodingUninterp = 32;
+
+ // ISO Encoding IDs
+ public static final short encodingASCII = 0;
+ public static final short encodingISO10646 = 1;
+ public static final short encodingISO8859_1 = 2;
+
+ // Microsoft Language IDs
+ public static final short languageSQI = 0x041c;
+ public static final short languageEUQ = 0x042d;
+ public static final short languageBEL = 0x0423;
+ public static final short languageBGR = 0x0402;
+ public static final short languageCAT = 0x0403;
+ public static final short languageSHL = 0x041a;
+ public static final short languageCSY = 0x0405;
+ public static final short languageDAN = 0x0406;
+ public static final short languageNLD = 0x0413;
+ public static final short languageNLB = 0x0813;
+ public static final short languageENU = 0x0409;
+ public static final short languageENG = 0x0809;
+ public static final short languageENA = 0x0c09;
+ public static final short languageENC = 0x1009;
+ public static final short languageENZ = 0x1409;
+ public static final short languageENI = 0x1809;
+ public static final short languageETI = 0x0425;
+ public static final short languageFIN = 0x040b;
+ public static final short languageFRA = 0x040c;
+ public static final short languageFRB = 0x080c;
+ public static final short languageFRC = 0x0c0c;
+ public static final short languageFRS = 0x100c;
+ public static final short languageFRL = 0x140c;
+ public static final short languageDEU = 0x0407;
+ public static final short languageDES = 0x0807;
+ public static final short languageDEA = 0x0c07;
+ public static final short languageDEL = 0x1007;
+ public static final short languageDEC = 0x1407;
+ public static final short languageELL = 0x0408;
+ public static final short languageHUN = 0x040e;
+ public static final short languageISL = 0x040f;
+ public static final short languageITA = 0x0410;
+ public static final short languageITS = 0x0810;
+ public static final short languageLVI = 0x0426;
+ public static final short languageLTH = 0x0427;
+ public static final short languageNOR = 0x0414;
+ public static final short languageNON = 0x0814;
+ public static final short languagePLK = 0x0415;
+ public static final short languagePTB = 0x0416;
+ public static final short languagePTG = 0x0816;
+ public static final short languageROM = 0x0418;
+ public static final short languageRUS = 0x0419;
+ public static final short languageSKY = 0x041b;
+ public static final short languageSLV = 0x0424;
+ public static final short languageESP = 0x040a;
+ public static final short languageESM = 0x080a;
+ public static final short languageESN = 0x0c0a;
+ public static final short languageSVE = 0x041d;
+ public static final short languageTRK = 0x041f;
+ public static final short languageUKR = 0x0422;
+
+ // Macintosh Language IDs
+ public static final short languageEnglish = 0;
+ public static final short languageFrench = 1;
+ public static final short languageGerman = 2;
+ public static final short languageItalian = 3;
+ public static final short languageDutch = 4;
+ public static final short languageSwedish = 5;
+ public static final short languageSpanish = 6;
+ public static final short languageDanish = 7;
+ public static final short languagePortuguese = 8;
+ public static final short languageNorwegian = 9;
+ public static final short languageHebrew = 10;
+ public static final short languageJapanese = 11;
+ public static final short languageArabic = 12;
+ public static final short languageFinnish = 13;
+ public static final short languageGreek = 14;
+ public static final short languageIcelandic = 15;
+ public static final short languageMaltese = 16;
+ public static final short languageTurkish = 17;
+ public static final short languageYugoslavian = 18;
+ public static final short languageChinese = 19;
+ public static final short languageUrdu = 20;
+ public static final short languageHindi = 21;
+ public static final short languageThai = 22;
+
+ // Name IDs
+ public static final short nameCopyrightNotice = 0;
+ public static final short nameFontFamilyName = 1;
+ public static final short nameFontSubfamilyName = 2;
+ public static final short nameUniqueFontIdentifier = 3;
+ public static final short nameFullFontName = 4;
+ public static final short nameVersionString = 5;
+ public static final short namePostscriptName = 6;
+ public static final short nameTrademark = 7;
+ public static final short nameManufacturerName = 8;
+ public static final short nameDesigner = 9;
+ public static final short nameDescription = 10;
+ public static final short nameURLVendor = 11;
+ public static final short nameURLDesigner = 12;
+ public static final short nameLicenseDescription = 13;
+ public static final short nameLicenseInfoURL = 14;
+ public static final short namePreferredFamily = 16;
+ public static final short namePreferredSubfamily = 17;
+ public static final short nameCompatibleFull = 18;
+ public static final short nameSampleText = 19;
+ public static final short namePostScriptCIDFindfontName = 20;
+
+ public static String getPlatformName(short platformId) {
+ switch (platformId) {
+ case platformUnicode: return "Unicode";
+ case platformMacintosh: return "Macintosh";
+ case platformISO: return "ISO";
+ case platformMicrosoft: return "Microsoft";
+ default: return "Custom";
+ }
+ }
+
+ public static String getEncodingName(short platformId, short encodingId) {
+
+ if (platformId == platformUnicode) {
+
+ // Unicode specific encodings
+ switch (encodingId) {
+ case encodingUnicode10Semantics: return "Unicode 1.0 semantics";
+ case encodingUnicode11Semantics: return "Unicode 1.1 semantics";
+ case encodingISO10646Semantics: return "ISO 10646:1993 semantics";
+ case encodingUnicode20Semantics: return "Unicode 2.0 and onwards semantics";
+ default: return "";
+ }
+
+ } else if (platformId == platformMacintosh) {
+
+ // Macintosh specific encodings
+ switch (encodingId) {
+ case encodingRoman: return "Roman";
+ case encodingJapanese: return "Japanese";
+ case encodingChinese: return "Chinese";
+ case encodingKorean: return "Korean";
+ case encodingArabic: return "Arabi";
+ case encodingHebrew: return "Hebrew";
+ case encodingGreek: return "Greek";
+ case encodingRussian: return "Russian";
+ case encodingRSymbol: return "RSymbol";
+ case encodingDevanagari: return "Devanagari";
+ case encodingGurmukhi: return "Gurmukhi";
+ case encodingGujarati: return "Gujarati";
+ case encodingOriya: return "Oriya";
+ case encodingBengali: return "Bengali";
+ case encodingTamil: return "Tamil";
+ case encodingTelugu: return "Telugu";
+ case encodingKannada: return "Kannada";
+ case encodingMalayalam: return "Malayalam";
+ case encodingSinhalese: return "Sinhalese";
+ case encodingBurmese: return "Burmese";
+ case encodingKhmer: return "Khmer";
+ case encodingThai: return "Thai";
+ case encodingLaotian: return "Laotian";
+ case encodingGeorgian: return "Georgian";
+ case encodingArmenian: return "Armenian";
+ case encodingMaldivian: return "Maldivian";
+ case encodingTibetan: return "Tibetan";
+ case encodingMongolian: return "Mongolian";
+ case encodingGeez: return "Geez";
+ case encodingSlavic: return "Slavic";
+ case encodingVietnamese: return "Vietnamese";
+ case encodingSindhi: return "Sindhi";
+ case encodingUninterp: return "Uninterpreted";
+ default: return "";
+ }
+
+ } else if (platformId == platformISO) {
+
+ // ISO specific encodings
+ switch (encodingId) {
+ case encodingASCII: return "7-bit ASCII";
+ case encodingISO10646: return "ISO 10646";
+ case encodingISO8859_1: return "ISO 8859-1";
+ default: return "";
+ }
+
+ } else if (platformId == platformMicrosoft) {
+
+ // Windows specific encodings
+ switch (encodingId) {
+ case encodingSymbol: return "Symbol";
+ case encodingUnicode: return "Unicode";
+ case encodingShiftJIS: return "ShiftJIS";
+ case encodingPRC: return "PRC";
+ case encodingBig5: return "Big5";
+ case encodingWansung: return "Wansung";
+ case encodingJohab: return "Johab";
+ case 7: return "Reserved";
+ case 8: return "Reserved";
+ case 9: return "Reserved";
+ case encodingUCS4: return "UCS-4";
+ default: return "";
+ }
+ }
+ return "";
+ }
+
+ public static String getLanguageName(short platformId, short languageId) {
+
+ if (platformId == platformMacintosh) {
+ switch (languageId) {
+ case languageEnglish: return "English";
+ case languageFrench: return "French";
+ case languageGerman: return "German";
+ case languageItalian: return "Italian";
+ case languageDutch: return "Dutch";
+ case languageSwedish: return "Swedish";
+ case languageSpanish: return "Spanish";
+ case languageDanish: return "Danish";
+ case languagePortuguese: return "Portuguese";
+ case languageNorwegian: return "Norwegian";
+ case languageHebrew: return "Hebrew";
+ case languageJapanese: return "Japanese";
+ case languageArabic: return "Arabic";
+ case languageFinnish: return "Finnish";
+ case languageGreek: return "Greek";
+ case languageIcelandic: return "Icelandic";
+ case languageMaltese: return "Maltese";
+ case languageTurkish: return "Turkish";
+ case languageYugoslavian: return "Yugoslavian";
+ case languageChinese: return "Chinese";
+ case languageUrdu: return "Urdu";
+ case languageHindi: return "Hindi";
+ case languageThai: return "Thai";
+ default: return "";
+ }
+ } else if (platformId == platformMicrosoft) {
+ switch (languageId) {
+ case languageSQI: return "Albanian (Albania)";
+ case languageEUQ: return "Basque (Basque)";
+ case languageBEL: return "Byelorussian (Byelorussia)";
+ case languageBGR: return "Bulgarian (Bulgaria)";
+ case languageCAT: return "Catalan (Catalan)";
+ case languageSHL: return "Croatian (Croatian)";
+ case languageCSY: return "Czech (Czech)";
+ case languageDAN: return "Danish (Danish)";
+ case languageNLD: return "Dutch (Dutch (Standard))";
+ case languageNLB: return "Dutch (Belgian (Flemish))";
+ case languageENU: return "English (American)";
+ case languageENG: return "English (British)";
+ case languageENA: return "English (Australian)";
+ case languageENC: return "English (Canadian)";
+ case languageENZ: return "English (New Zealand)";
+ case languageENI: return "English (Ireland)";
+ case languageETI: return "Estonian (Estonia)";
+ case languageFIN: return "Finnish (Finnish)";
+ case languageFRA: return "French (French (Standard))";
+ case languageFRB: return "French (Belgian)";
+ case languageFRC: return "French (Canadian)";
+ case languageFRS: return "French (Swiss)";
+ case languageFRL: return "French (Luxembourg)";
+ case languageDEU: return "German (German (Standard))";
+ case languageDES: return "German (Swiss)";
+ case languageDEA: return "German (Austrian)";
+ case languageDEL: return "German (Luxembourg)";
+ case languageDEC: return "German (Liechtenstein)";
+ case languageELL: return "Greek (Greek)";
+ case languageHUN: return "Hungarian (Hungarian)";
+ case languageISL: return "Icelandic (Icelandic)";
+ case languageITA: return "Italian (Italian (Standard))";
+ case languageITS: return "Italian (Swiss)";
+ case languageLVI: return "Latvian (Latvia)";
+ case languageLTH: return "Lithuanian (Lithuania)";
+ case languageNOR: return "Norwegian (Norwegian (Bokmal))";
+ case languageNON: return "Norwegian (Norwegian (Nynorsk))";
+ case languagePLK: return "Polish (Polish)";
+ case languagePTB: return "Portuguese (Portuguese (Brazilian))";
+ case languagePTG: return "Portuguese (Portuguese (Standard))";
+ case languageROM: return "Romanian (Romania)";
+ case languageRUS: return "Russian (Russian)";
+ case languageSKY: return "Slovak (Slovak)";
+ case languageSLV: return "Slovenian (Slovenia)";
+ case languageESP: return "Spanish (Spanish (Traditional Sort))";
+ case languageESM: return "Spanish (Mexican)";
+ case languageESN: return "Spanish (Spanish (Modern Sort))";
+ case languageSVE: return "Swedish (Swedish)";
+ case languageTRK: return "Turkish (Turkish)";
+ case languageUKR: return "Ukrainian (Ukraine)";
+ default: return "";
+ }
+ }
+ return "";
+ }
+
+ public static String getNameName(short nameId) {
+ switch (nameId) {
+ case nameCopyrightNotice: return "Copyright notice";
+ case nameFontFamilyName: return "Font Family name";
+ case nameFontSubfamilyName: return "Font Subfamily name";
+ case nameUniqueFontIdentifier: return "Unique font identifier";
+ case nameFullFontName: return "Full font name";
+ case nameVersionString: return "Version string";
+ case namePostscriptName: return "Postscript name";
+ case nameTrademark: return "Trademark";
+ case nameManufacturerName: return "Manufacturer Name";
+ case nameDesigner: return "Designer";
+ case nameDescription: return "Description";
+ case nameURLVendor: return "URL Vendor";
+ case nameURLDesigner: return "URL Designer";
+ case nameLicenseDescription: return "License Description";
+ case nameLicenseInfoURL: return "License Info URL";
+ case namePreferredFamily: return "Preferred Family";
+ case namePreferredSubfamily: return "Preferred Subfamily";
+ case nameCompatibleFull: return "Compatible Full";
+ case nameSampleText: return "Sample text";
+ case namePostScriptCIDFindfontName: return "PostScript CID findfont name";
+ default: return "";
+ }
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/KernSubtable.java b/src/typecast/net/java/dev/typecast/ot/table/KernSubtable.java
new file mode 100644
index 000000000..f55fa04fb
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/KernSubtable.java
@@ -0,0 +1,49 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: KernSubtable.java,v 1.1.1.1 2004-12-05 23:14:47 davidsch Exp $
+ */
+public abstract class KernSubtable {
+
+ /** Creates new KernSubtable */
+ protected KernSubtable() {
+ }
+
+ public abstract int getKerningPairCount();
+
+ public abstract KerningPair getKerningPair(int i);
+
+ public static KernSubtable read(DataInput di) throws IOException {
+ KernSubtable table = null;
+ int version = di.readUnsignedShort();
+ int length = di.readUnsignedShort();
+ int coverage = di.readUnsignedShort();
+ int format = coverage >> 8;
+
+ switch (format) {
+ case 0:
+ table = new KernSubtableFormat0(di);
+ break;
+ case 2:
+ table = new KernSubtableFormat2(di);
+ break;
+ default:
+ break;
+ }
+ return table;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat0.java b/src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat0.java
new file mode 100644
index 000000000..e3b1c9cf9
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat0.java
@@ -0,0 +1,47 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: KernSubtableFormat0.java,v 1.1.1.1 2004-12-05 23:14:48 davidsch Exp $
+ */
+public class KernSubtableFormat0 extends KernSubtable {
+
+ private int nPairs;
+ private int searchRange;
+ private int entrySelector;
+ private int rangeShift;
+ private KerningPair[] kerningPairs;
+
+ /** Creates new KernSubtableFormat0 */
+ protected KernSubtableFormat0(DataInput di) throws IOException {
+ nPairs = di.readUnsignedShort();
+ searchRange = di.readUnsignedShort();
+ entrySelector = di.readUnsignedShort();
+ rangeShift = di.readUnsignedShort();
+ kerningPairs = new KerningPair[nPairs];
+ for (int i = 0; i < nPairs; i++) {
+ kerningPairs[i] = new KerningPair(di);
+ }
+ }
+
+ public int getKerningPairCount() {
+ return nPairs;
+ }
+
+ public KerningPair getKerningPair(int i) {
+ return kerningPairs[i];
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat2.java b/src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat2.java
new file mode 100644
index 000000000..5ff37c291
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/KernSubtableFormat2.java
@@ -0,0 +1,42 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: KernSubtableFormat2.java,v 1.1.1.1 2004-12-05 23:14:48 davidsch Exp $
+ */
+public class KernSubtableFormat2 extends KernSubtable {
+
+ private int rowWidth;
+ private int leftClassTable;
+ private int rightClassTable;
+ private int array;
+
+ /** Creates new KernSubtableFormat2 */
+ protected KernSubtableFormat2(DataInput di) throws IOException {
+ rowWidth = di.readUnsignedShort();
+ leftClassTable = di.readUnsignedShort();
+ rightClassTable = di.readUnsignedShort();
+ array = di.readUnsignedShort();
+ }
+
+ public int getKerningPairCount() {
+ return 0;
+ }
+
+ public KerningPair getKerningPair(int i) {
+ return null;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/KernTable.java b/src/typecast/net/java/dev/typecast/ot/table/KernTable.java
new file mode 100644
index 000000000..81c4a998f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/KernTable.java
@@ -0,0 +1,62 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: KernTable.java,v 1.1.1.1 2004-12-05 23:14:48 davidsch Exp $
+ */
+public class KernTable implements Table {
+
+ private DirectoryEntry de;
+ private int version;
+ private int nTables;
+ private KernSubtable[] tables;
+
+ /** Creates new KernTable */
+ protected KernTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readUnsignedShort();
+ nTables = di.readUnsignedShort();
+ tables = new KernSubtable[nTables];
+ for (int i = 0; i < nTables; i++) {
+ tables[i] = KernSubtable.read(di);
+ }
+ }
+
+ public int getSubtableCount() {
+ return nTables;
+ }
+
+ public KernSubtable getSubtable(int i) {
+ return tables[i];
+ }
+
+ /** Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return kern;
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/KerningPair.java b/src/typecast/net/java/dev/typecast/ot/table/KerningPair.java
new file mode 100644
index 000000000..de614235f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/KerningPair.java
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: KerningPair.java,v 1.1.1.1 2004-12-05 23:14:47 davidsch Exp $
+ */
+public class KerningPair {
+
+ private int left;
+ private int right;
+ private short value;
+
+ /** Creates new KerningPair */
+ protected KerningPair(DataInput di) throws IOException {
+ left = di.readUnsignedShort();
+ right = di.readUnsignedShort();
+ value = di.readShort();
+ }
+
+ public int getLeft() {
+ return left;
+ }
+
+ public int getRight() {
+ return right;
+ }
+
+ public short getValue() {
+ return value;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LangSys.java b/src/typecast/net/java/dev/typecast/ot/table/LangSys.java
new file mode 100644
index 000000000..9963bf6af
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LangSys.java
@@ -0,0 +1,105 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LangSys.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class LangSys {
+
+ private int _lookupOrder;
+ private int _reqFeatureIndex;
+ private int _featureCount;
+ private int[] _featureIndex;
+
+ /** Creates new LangSys */
+ protected LangSys(DataInput di) throws IOException {
+ _lookupOrder = di.readUnsignedShort();
+ _reqFeatureIndex = di.readUnsignedShort();
+ _featureCount = di.readUnsignedShort();
+ _featureIndex = new int[_featureCount];
+ for (int i = 0; i < _featureCount; i++) {
+ _featureIndex[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getLookupOrder() {
+ return _lookupOrder;
+ }
+
+ public int getReqFeatureIndex() {
+ return _reqFeatureIndex;
+ }
+
+ public int getFeatureCount() {
+ return _featureCount;
+ }
+
+ public int getFeatureIndex(int i) {
+ return _featureIndex[i];
+ }
+
+ protected boolean isFeatureIndexed(int n) {
+ for (int i = 0; i < _featureCount; i++) {
+ if (_featureIndex[i] == n) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LangSysRecord.java b/src/typecast/net/java/dev/typecast/ot/table/LangSysRecord.java
new file mode 100644
index 000000000..a69c12a44
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LangSysRecord.java
@@ -0,0 +1,88 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LangSysRecord.java,v 1.2 2007-01-24 09:47:48 davidsch Exp $
+ */
+public class LangSysRecord {
+
+ private int _tag;
+ private int _offset;
+
+ /** Creates new LangSysRecord */
+ public LangSysRecord(DataInput di) throws IOException {
+ _tag = di.readInt();
+ _offset = di.readUnsignedShort();
+ }
+
+ public int getTag() {
+ return _tag;
+ }
+
+ public int getOffset() {
+ return _offset;
+ }
+
+ public String getTagAsString() {
+ return new StringBuffer()
+ .append((char)((_tag>>24)&0xff))
+ .append((char)((_tag>>16)&0xff))
+ .append((char)((_tag>>8)&0xff))
+ .append((char)((_tag)&0xff))
+ .toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Ligature.java b/src/typecast/net/java/dev/typecast/ot/table/Ligature.java
new file mode 100644
index 000000000..36969ba7a
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Ligature.java
@@ -0,0 +1,85 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Ligature.java,v 1.2 2007-01-24 09:47:48 davidsch Exp $
+ */
+public class Ligature {
+
+ private int _ligGlyph;
+ private int _compCount;
+ private int[] _components;
+
+ /** Creates new Ligature */
+ public Ligature(DataInput di) throws IOException {
+ _ligGlyph = di.readUnsignedShort();
+ _compCount = di.readUnsignedShort();
+ _components = new int[_compCount - 1];
+ for (int i = 0; i < _compCount - 1; i++) {
+ _components[i] = di.readUnsignedShort();
+ }
+ }
+
+ public int getGlyphCount() {
+ return _compCount;
+ }
+
+ public int getGlyphId(int i) {
+ return (i == 0) ? _ligGlyph : _components[i-1];
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LigatureSet.java b/src/typecast/net/java/dev/typecast/ot/table/LigatureSet.java
new file mode 100644
index 000000000..fe6db0445
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LigatureSet.java
@@ -0,0 +1,85 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LigatureSet.java,v 1.2 2007-01-24 09:47:46 davidsch Exp $
+ */
+public class LigatureSet {
+
+ private int _ligatureCount;
+ private int[] _ligatureOffsets;
+ private Ligature[] _ligatures;
+
+ /** Creates new LigatureSet */
+ public LigatureSet(DataInputStream dis, int offset) throws IOException {
+ dis.reset();
+ dis.skipBytes(offset);
+ _ligatureCount = dis.readUnsignedShort();
+ _ligatureOffsets = new int[_ligatureCount];
+ _ligatures = new Ligature[_ligatureCount];
+ for (int i = 0; i < _ligatureCount; i++) {
+ _ligatureOffsets[i] = dis.readUnsignedShort();
+ }
+ for (int i = 0; i < _ligatureCount; i++) {
+ dis.reset();
+ dis.skipBytes(offset + _ligatureOffsets[i]);
+ _ligatures[i] = new Ligature(dis);
+ }
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LigatureSubst.java b/src/typecast/net/java/dev/typecast/ot/table/LigatureSubst.java
new file mode 100644
index 000000000..73a8b9d36
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LigatureSubst.java
@@ -0,0 +1,73 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LigatureSubst.java,v 1.2 2007-01-24 09:47:48 davidsch Exp $
+ */
+public abstract class LigatureSubst extends LookupSubtable {
+
+ public static LigatureSubst read(DataInputStream dis, int offset) throws IOException {
+ dis.reset();
+ dis.skipBytes(offset);
+ int format = dis.readUnsignedShort();
+ if (format == 1) {
+ return new LigatureSubstFormat1(dis, offset);
+ }
+ return null;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LigatureSubstFormat1.java b/src/typecast/net/java/dev/typecast/ot/table/LigatureSubstFormat1.java
new file mode 100644
index 000000000..b19b07111
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LigatureSubstFormat1.java
@@ -0,0 +1,95 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LigatureSubstFormat1.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class LigatureSubstFormat1 extends LigatureSubst {
+
+ private int _coverageOffset;
+ private int _ligSetCount;
+ private int[] _ligatureSetOffsets;
+ private Coverage _coverage;
+ private LigatureSet[] _ligatureSets;
+
+ /** Creates new LigatureSubstFormat1 */
+ protected LigatureSubstFormat1(
+ DataInputStream dis,
+ int offset) throws IOException {
+ _coverageOffset = dis.readUnsignedShort();
+ _ligSetCount = dis.readUnsignedShort();
+ _ligatureSetOffsets = new int[_ligSetCount];
+ _ligatureSets = new LigatureSet[_ligSetCount];
+ for (int i = 0; i < _ligSetCount; i++) {
+ _ligatureSetOffsets[i] = dis.readUnsignedShort();
+ }
+ dis.reset();
+ dis.skipBytes(offset + _coverageOffset);
+ _coverage = Coverage.read(dis);
+ for (int i = 0; i < _ligSetCount; i++) {
+ _ligatureSets[i] = new LigatureSet(dis, offset + _ligatureSetOffsets[i]);
+ }
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+ public String getTypeAsString() {
+ return "LigatureSubstFormat1";
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LocaTable.java b/src/typecast/net/java/dev/typecast/ot/table/LocaTable.java
new file mode 100644
index 000000000..5f62940df
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LocaTable.java
@@ -0,0 +1,77 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: LocaTable.java,v 1.4 2010-08-10 11:45:43 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class LocaTable implements Table {
+
+ private DirectoryEntry _de;
+ private int[] _offsets = null;
+ private short _factor = 0;
+
+ protected LocaTable(
+ DirectoryEntry de,
+ DataInput di,
+ HeadTable head,
+ MaxpTable maxp) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _offsets = new int[maxp.getNumGlyphs() + 1];
+ boolean shortEntries = head.getIndexToLocFormat() == 0;
+ if (shortEntries) {
+ _factor = 2;
+ for (int i = 0; i <= maxp.getNumGlyphs(); i++) {
+ _offsets[i] = di.readUnsignedShort();
+ }
+ } else {
+ _factor = 1;
+ for (int i = 0; i <= maxp.getNumGlyphs(); i++) {
+ _offsets[i] = di.readInt();
+ }
+ }
+ }
+
+ public int getOffset(int i) {
+ if (_offsets == null) {
+ return 0;
+ }
+ return _offsets[i] * _factor;
+ }
+
+ public int getType() {
+ return loca;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'loca' Table - Index To Location Table\n--------------------------------------\n")
+ .append("Size = ").append(_de.getLength()).append(" bytes, ")
+ .append(_offsets.length).append(" entries\n");
+ for (int i = 0; i < _offsets.length; i++) {
+ sb.append(" Idx ").append(i)
+ .append(" -> glyfOff 0x").append(getOffset(i)).append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Lookup.java b/src/typecast/net/java/dev/typecast/ot/table/Lookup.java
new file mode 100644
index 000000000..d6e46cd91
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Lookup.java
@@ -0,0 +1,110 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Lookup.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class Lookup {
+
+ // LookupFlag bit enumeration
+ public static final int IGNORE_BASE_GLYPHS = 0x0002;
+ public static final int IGNORE_BASE_LIGATURES = 0x0004;
+ public static final int IGNORE_BASE_MARKS = 0x0008;
+ public static final int MARK_ATTACHMENT_TYPE = 0xFF00;
+
+ private int _type;
+ private int _flag;
+ private int _subTableCount;
+ private int[] _subTableOffsets;
+ private LookupSubtable[] _subTables;
+
+ /** Creates new Lookup */
+ public Lookup(LookupSubtableFactory factory, DataInputStream dis, int offset)
+ throws IOException {
+
+ // Ensure we're in the right place
+ dis.reset();
+ dis.skipBytes(offset);
+
+ // Start reading
+ _type = dis.readUnsignedShort();
+ _flag = dis.readUnsignedShort();
+ _subTableCount = dis.readUnsignedShort();
+ _subTableOffsets = new int[_subTableCount];
+ _subTables = new LookupSubtable[_subTableCount];
+ for (int i = 0; i < _subTableCount; i++) {
+ _subTableOffsets[i] = dis.readUnsignedShort();
+ }
+ for (int i = 0; i < _subTableCount; i++) {
+ _subTables[i] = factory.read(_type, dis, offset + _subTableOffsets[i]);
+ }
+ }
+
+ public int getType() {
+ return _type;
+ }
+
+ public int getSubtableCount() {
+ return _subTableCount;
+ }
+
+ public LookupSubtable getSubtable(int i) {
+ return _subTables[i];
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LookupList.java b/src/typecast/net/java/dev/typecast/ot/table/LookupList.java
new file mode 100644
index 000000000..9ac76aba5
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LookupList.java
@@ -0,0 +1,108 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LookupList.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class LookupList {
+
+ private int _lookupCount;
+ private int[] _lookupOffsets;
+ private Lookup[] _lookups;
+
+ /** Creates new LookupList */
+ public LookupList(DataInputStream dis, int offset, LookupSubtableFactory factory)
+ throws IOException {
+
+ // Ensure we're in the right place
+ dis.reset();
+ dis.skipBytes(offset);
+
+ // Start reading
+ _lookupCount = dis.readUnsignedShort();
+ _lookupOffsets = new int[_lookupCount];
+ _lookups = new Lookup[_lookupCount];
+ for (int i = 0; i < _lookupCount; i++) {
+ _lookupOffsets[i] = dis.readUnsignedShort();
+ }
+ for (int i = 0; i < _lookupCount; i++) {
+ _lookups[i] = new Lookup(factory, dis, offset + _lookupOffsets[i]);
+ }
+ }
+
+ public int getLookupCount() {
+ return _lookupCount;
+ }
+
+ public int getLookupOffset(int i) {
+ return _lookupOffsets[i];
+ }
+
+ public Lookup getLookup(int i) {
+ return _lookups[i];
+ }
+
+ public Lookup getLookup(Feature feature, int index) {
+ if (feature.getLookupCount() > index) {
+ int i = feature.getLookupListIndex(index);
+ return _lookups[i];
+ }
+ return null;
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LookupSubtable.java b/src/typecast/net/java/dev/typecast/ot/table/LookupSubtable.java
new file mode 100644
index 000000000..4d8dbb180
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LookupSubtable.java
@@ -0,0 +1,60 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LookupSubtable.java,v 1.2 2007-01-24 09:47:45 davidsch Exp $
+ */
+public abstract class LookupSubtable {
+ public abstract String getTypeAsString();
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LookupSubtableFactory.java b/src/typecast/net/java/dev/typecast/ot/table/LookupSubtableFactory.java
new file mode 100644
index 000000000..2081e2ea6
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LookupSubtableFactory.java
@@ -0,0 +1,64 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: LookupSubtableFactory.java,v 1.2 2007-01-24 09:47:46 davidsch Exp $
+ */
+public interface LookupSubtableFactory {
+ public LookupSubtable read(int type, DataInputStream dis, int offset)
+ throws IOException;
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/LtshTable.java b/src/typecast/net/java/dev/typecast/ot/table/LtshTable.java
new file mode 100644
index 000000000..12dca01f4
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/LtshTable.java
@@ -0,0 +1,68 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @version $Id: LtshTable.java,v 1.1.1.1 2004-12-05 23:14:51 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class LtshTable implements Table {
+
+ private DirectoryEntry de;
+ private int version;
+ private int numGlyphs;
+ private int[] yPels;
+
+ /** Creates new LtshTable */
+ protected LtshTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readUnsignedShort();
+ numGlyphs = di.readUnsignedShort();
+ yPels = new int[numGlyphs];
+ for (int i = 0; i < numGlyphs; i++) {
+ yPels[i] = di.readUnsignedByte();
+ }
+ }
+
+ /**
+ * Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return LTSH;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'LTSH' Table - Linear Threshold Table\n-------------------------------------")
+ .append("\n 'LTSH' Version: ").append(version)
+ .append("\n Number of Glyphs: ").append(numGlyphs)
+ .append("\n\n Glyph # Threshold\n ------- ---------\n");
+ for (int i = 0; i < numGlyphs; i++) {
+ sb.append(" ").append(i).append(". ").append(yPels[i])
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/MaxpTable.java b/src/typecast/net/java/dev/typecast/ot/table/MaxpTable.java
new file mode 100644
index 000000000..571d3ebfd
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/MaxpTable.java
@@ -0,0 +1,162 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Fixed;
+
+/**
+ * @version $Id: MaxpTable.java,v 1.1.1.1 2004-12-05 23:14:52 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class MaxpTable implements Table {
+
+ private DirectoryEntry de;
+ private int versionNumber;
+ private int numGlyphs;
+ private int maxPoints;
+ private int maxContours;
+ private int maxCompositePoints;
+ private int maxCompositeContours;
+ private int maxZones;
+ private int maxTwilightPoints;
+ private int maxStorage;
+ private int maxFunctionDefs;
+ private int maxInstructionDefs;
+ private int maxStackElements;
+ private int maxSizeOfInstructions;
+ private int maxComponentElements;
+ private int maxComponentDepth;
+
+ protected MaxpTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ versionNumber = di.readInt();
+
+ // CFF fonts use version 0.5, TrueType fonts use version 1.0
+ if (versionNumber == 0x00005000) {
+ numGlyphs = di.readUnsignedShort();
+ } else if (versionNumber == 0x00010000) {
+ numGlyphs = di.readUnsignedShort();
+ maxPoints = di.readUnsignedShort();
+ maxContours = di.readUnsignedShort();
+ maxCompositePoints = di.readUnsignedShort();
+ maxCompositeContours = di.readUnsignedShort();
+ maxZones = di.readUnsignedShort();
+ maxTwilightPoints = di.readUnsignedShort();
+ maxStorage = di.readUnsignedShort();
+ maxFunctionDefs = di.readUnsignedShort();
+ maxInstructionDefs = di.readUnsignedShort();
+ maxStackElements = di.readUnsignedShort();
+ maxSizeOfInstructions = di.readUnsignedShort();
+ maxComponentElements = di.readUnsignedShort();
+ maxComponentDepth = di.readUnsignedShort();
+ }
+ }
+
+ public int getVersionNumber() {
+ return versionNumber;
+ }
+
+ public int getMaxComponentDepth() {
+ return maxComponentDepth;
+ }
+
+ public int getMaxComponentElements() {
+ return maxComponentElements;
+ }
+
+ public int getMaxCompositeContours() {
+ return maxCompositeContours;
+ }
+
+ public int getMaxCompositePoints() {
+ return maxCompositePoints;
+ }
+
+ public int getMaxContours() {
+ return maxContours;
+ }
+
+ public int getMaxFunctionDefs() {
+ return maxFunctionDefs;
+ }
+
+ public int getMaxInstructionDefs() {
+ return maxInstructionDefs;
+ }
+
+ public int getMaxPoints() {
+ return maxPoints;
+ }
+
+ public int getMaxSizeOfInstructions() {
+ return maxSizeOfInstructions;
+ }
+
+ public int getMaxStackElements() {
+ return maxStackElements;
+ }
+
+ public int getMaxStorage() {
+ return maxStorage;
+ }
+
+ public int getMaxTwilightPoints() {
+ return maxTwilightPoints;
+ }
+
+ public int getMaxZones() {
+ return maxZones;
+ }
+
+ public int getNumGlyphs() {
+ return numGlyphs;
+ }
+
+ public int getType() {
+ return maxp;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'maxp' Table - Maximum Profile\n------------------------------")
+ .append("\n 'maxp' version: ").append(Fixed.floatValue(versionNumber))
+ .append("\n numGlyphs: ").append(numGlyphs);
+ if (versionNumber == 0x00010000) {
+ sb.append("\n maxPoints: ").append(maxPoints)
+ .append("\n maxContours: ").append(maxContours)
+ .append("\n maxCompositePoints: ").append(maxCompositePoints)
+ .append("\n maxCompositeContours: ").append(maxCompositeContours)
+ .append("\n maxZones: ").append(maxZones)
+ .append("\n maxTwilightPoints: ").append(maxTwilightPoints)
+ .append("\n maxStorage: ").append(maxStorage)
+ .append("\n maxFunctionDefs: ").append(maxFunctionDefs)
+ .append("\n maxInstructionDefs: ").append(maxInstructionDefs)
+ .append("\n maxStackElements: ").append(maxStackElements)
+ .append("\n maxSizeOfInstructions: ").append(maxSizeOfInstructions)
+ .append("\n maxComponentElements: ").append(maxComponentElements)
+ .append("\n maxComponentDepth: ").append(maxComponentDepth);
+ } else {
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/NameRecord.java b/src/typecast/net/java/dev/typecast/ot/table/NameRecord.java
new file mode 100644
index 000000000..cdba03ef9
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/NameRecord.java
@@ -0,0 +1,145 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: NameRecord.java,v 1.2 2004-12-09 23:47:23 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class NameRecord {
+
+ private short _platformId;
+ private short _encodingId;
+ private short _languageId;
+ private short _nameId;
+ private short _stringLength;
+ private short _stringOffset;
+ private String _record;
+
+ protected NameRecord(DataInput di) throws IOException {
+ _platformId = di.readShort();
+ _encodingId = di.readShort();
+ _languageId = di.readShort();
+ _nameId = di.readShort();
+ _stringLength = di.readShort();
+ _stringOffset = di.readShort();
+ }
+
+ public short getEncodingId() {
+ return _encodingId;
+ }
+
+ public short getLanguageId() {
+ return _languageId;
+ }
+
+ public short getNameId() {
+ return _nameId;
+ }
+
+ public short getPlatformId() {
+ return _platformId;
+ }
+
+ public String getRecordString() {
+ return _record;
+ }
+
+ protected void loadString(DataInput di) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ di.skipBytes(_stringOffset);
+ if (_platformId == ID.platformUnicode) {
+
+ // Unicode (big-endian)
+ for (int i = 0; i < _stringLength/2; i++) {
+ sb.append(di.readChar());
+ }
+ } else if (_platformId == ID.platformMacintosh) {
+
+ // Macintosh encoding, ASCII
+ for (int i = 0; i < _stringLength; i++) {
+ sb.append((char) di.readByte());
+ }
+ } else if (_platformId == ID.platformISO) {
+
+ // ISO encoding, ASCII
+ for (int i = 0; i < _stringLength; i++) {
+ sb.append((char) di.readByte());
+ }
+ } else if (_platformId == ID.platformMicrosoft) {
+
+ // Microsoft encoding, Unicode
+ char c;
+ for (int i = 0; i < _stringLength/2; i++) {
+ c = di.readChar();
+ sb.append(c);
+ }
+ }
+ _record = sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append(" Platform ID: ").append(_platformId)
+ .append("\n Specific ID: ").append(_encodingId)
+ .append("\n Language ID: ").append(_languageId)
+ .append("\n Name ID: ").append(_nameId)
+ .append("\n Length: ").append(_stringLength)
+ .append("\n Offset: ").append(_stringOffset)
+ .append("\n\n").append(_record);
+
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/NameTable.java b/src/typecast/net/java/dev/typecast/ot/table/NameTable.java
new file mode 100644
index 000000000..05f823427
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/NameTable.java
@@ -0,0 +1,131 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+/**
+ * The naming table allows multilingual strings to be associated with the
+ * OpenType font file. These strings can represent copyright notices, font
+ * names, family names, style names, and so on.
+ * @version $Id: NameTable.java,v 1.2 2004-12-09 23:47:23 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class NameTable implements Table {
+
+ private DirectoryEntry _de;
+ private short _formatSelector;
+ private short _numberOfNameRecords;
+ private short _stringStorageOffset;
+ private NameRecord[] _records;
+
+ protected NameTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _formatSelector = di.readShort();
+ _numberOfNameRecords = di.readShort();
+ _stringStorageOffset = di.readShort();
+ _records = new NameRecord[_numberOfNameRecords];
+
+ // Load the records, which contain the encoding information and string
+ // offsets
+ for (int i = 0; i < _numberOfNameRecords; i++) {
+ _records[i] = new NameRecord(di);
+ }
+
+ // Load the string data into a buffer so the records can copy out the
+ // bits they are interested in
+ byte[] buffer = new byte[_de.getLength() - _stringStorageOffset];
+ di.readFully(buffer);
+
+ // Now let the records get their hands on them
+ for (int i = 0; i < _numberOfNameRecords; i++) {
+ _records[i].loadString(
+ new DataInputStream(new ByteArrayInputStream(buffer)));
+ }
+ }
+
+ public short getNumberOfNameRecords() {
+ return _numberOfNameRecords;
+ }
+
+ public NameRecord getRecord(int i) {
+ return _records[i];
+ }
+
+ public String getRecordString(short nameId) {
+
+ // Search for the first instance of this name ID
+ for (int i = 0; i < _numberOfNameRecords; i++) {
+ if (_records[i].getNameId() == nameId) {
+ return _records[i].getRecordString();
+ }
+ }
+ return "";
+ }
+
+ public int getType() {
+ return name;
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Os2Table.java b/src/typecast/net/java/dev/typecast/ot/table/Os2Table.java
new file mode 100644
index 000000000..9ec599724
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Os2Table.java
@@ -0,0 +1,357 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: Os2Table.java,v 1.2 2004-12-09 23:46:21 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class Os2Table implements Table {
+
+ private DirectoryEntry _de;
+ private int _version;
+ private short _xAvgCharWidth;
+ private int _usWeightClass;
+ private int _usWidthClass;
+ private short _fsType;
+ private short _ySubscriptXSize;
+ private short _ySubscriptYSize;
+ private short _ySubscriptXOffset;
+ private short _ySubscriptYOffset;
+ private short _ySuperscriptXSize;
+ private short _ySuperscriptYSize;
+ private short _ySuperscriptXOffset;
+ private short _ySuperscriptYOffset;
+ private short _yStrikeoutSize;
+ private short _yStrikeoutPosition;
+ private short _sFamilyClass;
+ private Panose _panose;
+ private int _ulUnicodeRange1;
+ private int _ulUnicodeRange2;
+ private int _ulUnicodeRange3;
+ private int _ulUnicodeRange4;
+ private int _achVendorID;
+ private short _fsSelection;
+ private int _usFirstCharIndex;
+ private int _usLastCharIndex;
+ private short _sTypoAscender;
+ private short _sTypoDescender;
+ private short _sTypoLineGap;
+ private int _usWinAscent;
+ private int _usWinDescent;
+ private int _ulCodePageRange1;
+ private int _ulCodePageRange2;
+ private short _sxHeight;
+ private short _sCapHeight;
+ private int _usDefaultChar;
+ private int _usBreakChar;
+ private int _usMaxContext;
+
+ protected Os2Table(DirectoryEntry de, DataInput di) throws IOException {
+ this._de = (DirectoryEntry) de.clone();
+ _version = di.readUnsignedShort();
+ _xAvgCharWidth = di.readShort();
+ _usWeightClass = di.readUnsignedShort();
+ _usWidthClass = di.readUnsignedShort();
+ _fsType = di.readShort();
+ _ySubscriptXSize = di.readShort();
+ _ySubscriptYSize = di.readShort();
+ _ySubscriptXOffset = di.readShort();
+ _ySubscriptYOffset = di.readShort();
+ _ySuperscriptXSize = di.readShort();
+ _ySuperscriptYSize = di.readShort();
+ _ySuperscriptXOffset = di.readShort();
+ _ySuperscriptYOffset = di.readShort();
+ _yStrikeoutSize = di.readShort();
+ _yStrikeoutPosition = di.readShort();
+ _sFamilyClass = di.readShort();
+ byte[] buf = new byte[10];
+ di.readFully(buf);
+ _panose = new Panose(buf);
+ _ulUnicodeRange1 = di.readInt();
+ _ulUnicodeRange2 = di.readInt();
+ _ulUnicodeRange3 = di.readInt();
+ _ulUnicodeRange4 = di.readInt();
+ _achVendorID = di.readInt();
+ _fsSelection = di.readShort();
+ _usFirstCharIndex = di.readUnsignedShort();
+ _usLastCharIndex = di.readUnsignedShort();
+ _sTypoAscender = di.readShort();
+ _sTypoDescender = di.readShort();
+ _sTypoLineGap = di.readShort();
+ _usWinAscent = di.readUnsignedShort();
+ _usWinDescent = di.readUnsignedShort();
+ _ulCodePageRange1 = di.readInt();
+ _ulCodePageRange2 = di.readInt();
+
+ // OpenType 1.3
+ if (_version == 2) {
+ _sxHeight = di.readShort();
+ _sCapHeight = di.readShort();
+ _usDefaultChar = di.readUnsignedShort();
+ _usBreakChar = di.readUnsignedShort();
+ _usMaxContext = di.readUnsignedShort();
+ }
+ }
+
+ public int getVersion() {
+ return _version;
+ }
+
+ public short getAvgCharWidth() {
+ return _xAvgCharWidth;
+ }
+
+ public int getWeightClass() {
+ return _usWeightClass;
+ }
+
+ public int getWidthClass() {
+ return _usWidthClass;
+ }
+
+ public short getLicenseType() {
+ return _fsType;
+ }
+
+ public short getSubscriptXSize() {
+ return _ySubscriptXSize;
+ }
+
+ public short getSubscriptYSize() {
+ return _ySubscriptYSize;
+ }
+
+ public short getSubscriptXOffset() {
+ return _ySubscriptXOffset;
+ }
+
+ public short getSubscriptYOffset() {
+ return _ySubscriptYOffset;
+ }
+
+ public short getSuperscriptXSize() {
+ return _ySuperscriptXSize;
+ }
+
+ public short getSuperscriptYSize() {
+ return _ySuperscriptYSize;
+ }
+
+ public short getSuperscriptXOffset() {
+ return _ySuperscriptXOffset;
+ }
+
+ public short getSuperscriptYOffset() {
+ return _ySuperscriptYOffset;
+ }
+
+ public short getStrikeoutSize() {
+ return _yStrikeoutSize;
+ }
+
+ public short getStrikeoutPosition() {
+ return _yStrikeoutPosition;
+ }
+
+ public short getFamilyClass() {
+ return _sFamilyClass;
+ }
+
+ public Panose getPanose() {
+ return _panose;
+ }
+
+ public int getUnicodeRange1() {
+ return _ulUnicodeRange1;
+ }
+
+ public int getUnicodeRange2() {
+ return _ulUnicodeRange2;
+ }
+
+ public int getUnicodeRange3() {
+ return _ulUnicodeRange3;
+ }
+
+ public int getUnicodeRange4() {
+ return _ulUnicodeRange4;
+ }
+
+ public int getVendorID() {
+ return _achVendorID;
+ }
+
+ public short getSelection() {
+ return _fsSelection;
+ }
+
+ public int getFirstCharIndex() {
+ return _usFirstCharIndex;
+ }
+
+ public int getLastCharIndex() {
+ return _usLastCharIndex;
+ }
+
+ public short getTypoAscender() {
+ return _sTypoAscender;
+ }
+
+ public short getTypoDescender() {
+ return _sTypoDescender;
+ }
+
+ public short getTypoLineGap() {
+ return _sTypoLineGap;
+ }
+
+ public int getWinAscent() {
+ return _usWinAscent;
+ }
+
+ public int getWinDescent() {
+ return _usWinDescent;
+ }
+
+ public int getCodePageRange1() {
+ return _ulCodePageRange1;
+ }
+
+ public int getCodePageRange2() {
+ return _ulCodePageRange2;
+ }
+
+ public short getXHeight() {
+ return _sxHeight;
+ }
+
+ public short getCapHeight() {
+ return _sCapHeight;
+ }
+
+ public int getDefaultChar() {
+ return _usDefaultChar;
+ }
+
+ public int getBreakChar() {
+ return _usBreakChar;
+ }
+
+ public int getMaxContext() {
+ return _usMaxContext;
+ }
+
+ public int getType() {
+ return OS_2;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("'OS/2' Table - OS/2 and Windows Metrics\n---------------------------------------")
+ .append("\n 'OS/2' version: ").append(_version)
+ .append("\n xAvgCharWidth: ").append(_xAvgCharWidth)
+ .append("\n usWeightClass: ").append(_usWeightClass)
+ .append("\n usWidthClass: ").append(_usWidthClass)
+ .append("\n fsType: 0x").append(Integer.toHexString(_fsType).toUpperCase())
+ .append("\n ySubscriptXSize: ").append(_ySubscriptXSize)
+ .append("\n ySubscriptYSize: ").append(_ySubscriptYSize)
+ .append("\n ySubscriptXOffset: ").append(_ySubscriptXOffset)
+ .append("\n ySubscriptYOffset: ").append(_ySubscriptYOffset)
+ .append("\n ySuperscriptXSize: ").append(_ySuperscriptXSize)
+ .append("\n ySuperscriptYSize: ").append(_ySuperscriptYSize)
+ .append("\n ySuperscriptXOffset: ").append(_ySuperscriptXOffset)
+ .append("\n ySuperscriptYOffset: ").append(_ySuperscriptYOffset)
+ .append("\n yStrikeoutSize: ").append(_yStrikeoutSize)
+ .append("\n yStrikeoutPosition: ").append(_yStrikeoutPosition)
+ .append("\n sFamilyClass: ").append(_sFamilyClass>>8)
+ .append(" subclass = ").append(_sFamilyClass&0xff)
+ .append("\n PANOSE: ").append(_panose.toString())
+ .append("\n Unicode Range 1( Bits 0 - 31 ): ").append(Integer.toHexString(_ulUnicodeRange1).toUpperCase())
+ .append("\n Unicode Range 2( Bits 32- 63 ): ").append(Integer.toHexString(_ulUnicodeRange2).toUpperCase())
+ .append("\n Unicode Range 3( Bits 64- 95 ): ").append(Integer.toHexString(_ulUnicodeRange3).toUpperCase())
+ .append("\n Unicode Range 4( Bits 96-127 ): ").append(Integer.toHexString(_ulUnicodeRange4).toUpperCase())
+ .append("\n achVendID: '").append(getVendorIDAsString())
+ .append("'\n fsSelection: 0x").append(Integer.toHexString(_fsSelection).toUpperCase())
+ .append("\n usFirstCharIndex: 0x").append(Integer.toHexString(_usFirstCharIndex).toUpperCase())
+ .append("\n usLastCharIndex: 0x").append(Integer.toHexString(_usLastCharIndex).toUpperCase())
+ .append("\n sTypoAscender: ").append(_sTypoAscender)
+ .append("\n sTypoDescender: ").append(_sTypoDescender)
+ .append("\n sTypoLineGap: ").append(_sTypoLineGap)
+ .append("\n usWinAscent: ").append(_usWinAscent)
+ .append("\n usWinDescent: ").append(_usWinDescent)
+ .append("\n CodePage Range 1( Bits 0 - 31 ): ").append(Integer.toHexString(_ulCodePageRange1).toUpperCase())
+ .append("\n CodePage Range 2( Bits 32- 63 ): ").append(Integer.toHexString(_ulCodePageRange2).toUpperCase())
+ .toString();
+ }
+
+ private String getVendorIDAsString() {
+ return new StringBuffer()
+ .append((char)((_achVendorID>>24)&0xff))
+ .append((char)((_achVendorID>>16)&0xff))
+ .append((char)((_achVendorID>>8)&0xff))
+ .append((char)((_achVendorID)&0xff))
+ .toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Panose.java b/src/typecast/net/java/dev/typecast/ot/table/Panose.java
new file mode 100644
index 000000000..fe0a357d2
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Panose.java
@@ -0,0 +1,96 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * @version $Id: Panose.java,v 1.1.1.1 2004-12-05 23:14:54 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class Panose {
+
+ byte bFamilyType = 0;
+ byte bSerifStyle = 0;
+ byte bWeight = 0;
+ byte bProportion = 0;
+ byte bContrast = 0;
+ byte bStrokeVariation = 0;
+ byte bArmStyle = 0;
+ byte bLetterform = 0;
+ byte bMidline = 0;
+ byte bXHeight = 0;
+
+ /** Creates new Panose */
+ public Panose(byte[] panose) {
+ bFamilyType = panose[0];
+ bSerifStyle = panose[1];
+ bWeight = panose[2];
+ bProportion = panose[3];
+ bContrast = panose[4];
+ bStrokeVariation = panose[5];
+ bArmStyle = panose[6];
+ bLetterform = panose[7];
+ bMidline = panose[8];
+ bXHeight = panose[9];
+ }
+
+ public byte getFamilyType() {
+ return bFamilyType;
+ }
+
+ public byte getSerifStyle() {
+ return bSerifStyle;
+ }
+
+ public byte getWeight() {
+ return bWeight;
+ }
+
+ public byte getProportion() {
+ return bProportion;
+ }
+
+ public byte getContrast() {
+ return bContrast;
+ }
+
+ public byte getStrokeVariation() {
+ return bStrokeVariation;
+ }
+
+ public byte getArmStyle() {
+ return bArmStyle;
+ }
+
+ public byte getLetterForm() {
+ return bLetterform;
+ }
+
+ public byte getMidline() {
+ return bMidline;
+ }
+
+ public byte getXHeight() {
+ return bXHeight;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(String.valueOf(bFamilyType)).append(" ")
+ .append(String.valueOf(bSerifStyle)).append(" ")
+ .append(String.valueOf(bWeight)).append(" ")
+ .append(String.valueOf(bProportion)).append(" ")
+ .append(String.valueOf(bContrast)).append(" ")
+ .append(String.valueOf(bStrokeVariation)).append(" ")
+ .append(String.valueOf(bArmStyle)).append(" ")
+ .append(String.valueOf(bLetterform)).append(" ")
+ .append(String.valueOf(bMidline)).append(" ")
+ .append(String.valueOf(bXHeight));
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/PcltTable.java b/src/typecast/net/java/dev/typecast/ot/table/PcltTable.java
new file mode 100644
index 000000000..457aec2e1
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/PcltTable.java
@@ -0,0 +1,105 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @version $Id: PcltTable.java,v 1.1.1.1 2004-12-05 23:14:54 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class PcltTable implements Table {
+
+ private DirectoryEntry de;
+ private int version;
+ private long fontNumber;
+ private int pitch;
+ private int xHeight;
+ private int style;
+ private int typeFamily;
+ private int capHeight;
+ private int symbolSet;
+ private char[] typeface = new char[16];
+ private short[] characterComplement = new short[8];
+ private char[] fileName = new char[6];
+ private short strokeWeight;
+ private short widthType;
+ private byte serifStyle;
+ private byte reserved;
+
+ /** Creates new PcltTable */
+ protected PcltTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readInt();
+ fontNumber = di.readInt();
+ pitch = di.readUnsignedShort();
+ xHeight = di.readUnsignedShort();
+ style = di.readUnsignedShort();
+ typeFamily = di.readUnsignedShort();
+ capHeight = di.readUnsignedShort();
+ symbolSet = di.readUnsignedShort();
+ for (int i = 0; i < 16; i++) {
+ typeface[i] = (char) di.readUnsignedByte();
+ }
+ for (int i = 0; i < 8; i++) {
+ characterComplement[i] = (short) di.readUnsignedByte();
+ }
+ for (int i = 0; i < 6; i++) {
+ fileName[i] = (char) di.readUnsignedByte();
+ }
+ strokeWeight = (short) di.readUnsignedByte();
+ widthType = (short) di.readUnsignedByte();
+ serifStyle = di.readByte();
+ reserved = di.readByte();
+ }
+
+ /**
+ * Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return PCLT;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("'PCLT' Table - Printer Command Language Table\n---------------------------------------------")
+ .append("\n version: 0x").append(Integer.toHexString(version).toUpperCase())
+ .append("\n fontNumber: ").append(fontNumber).append(" (0x").append(Long.toHexString(fontNumber).toUpperCase())
+ .append(")\n pitch: ").append(pitch)
+ .append("\n xHeight: ").append(xHeight)
+ .append("\n style: 0x").append(style)
+ .append("\n typeFamily: 0x").append(typeFamily>>12)
+ .append(" ").append(typeFamily & 0xfff)
+ .append("\n capHeight: ").append(capHeight)
+ .append("\n symbolSet: ").append(symbolSet)
+ .append("\n typeFace: ").append(new String(typeface))
+ .append("\n characterComplement 0x")
+ .append(Integer.toHexString(characterComplement[0]).toUpperCase())
+ .append("\n fileName: ").append(new String(fileName))
+ .append("\n strokeWeight: ").append(strokeWeight)
+ .append("\n widthType: ").append(widthType)
+ .append("\n serifStyle: ").append(serifStyle)
+ .append("\n reserved: ").append(reserved)
+ .toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/PostTable.java b/src/typecast/net/java/dev/typecast/ot/table/PostTable.java
new file mode 100644
index 000000000..4a1b0650b
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/PostTable.java
@@ -0,0 +1,422 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Fixed;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: PostTable.java,v 1.1.1.1 2004-12-05 23:14:56 davidsch Exp $
+ */
+public class PostTable implements Table {
+
+ /**
+ * TODO: Mac Glyph names for 210 & 257
+ */
+ private static final String[] macGlyphName = {
+ ".notdef", // 0
+ "null", // 1
+ "CR", // 2
+ "space", // 3
+ "exclam", // 4
+ "quotedbl", // 5
+ "numbersign", // 6
+ "dollar", // 7
+ "percent", // 8
+ "ampersand", // 9
+ "quotesingle", // 10
+ "parenleft", // 11
+ "parenright", // 12
+ "asterisk", // 13
+ "plus", // 14
+ "comma", // 15
+ "hyphen", // 16
+ "period", // 17
+ "slash", // 18
+ "zero", // 19
+ "one", // 20
+ "two", // 21
+ "three", // 22
+ "four", // 23
+ "five", // 24
+ "six", // 25
+ "seven", // 26
+ "eight", // 27
+ "nine", // 28
+ "colon", // 29
+ "semicolon", // 30
+ "less", // 31
+ "equal", // 32
+ "greater", // 33
+ "question", // 34
+ "at", // 35
+ "A", // 36
+ "B", // 37
+ "C", // 38
+ "D", // 39
+ "E", // 40
+ "F", // 41
+ "G", // 42
+ "H", // 43
+ "I", // 44
+ "J", // 45
+ "K", // 46
+ "L", // 47
+ "M", // 48
+ "N", // 49
+ "O", // 50
+ "P", // 51
+ "Q", // 52
+ "R", // 53
+ "S", // 54
+ "T", // 55
+ "U", // 56
+ "V", // 57
+ "W", // 58
+ "X", // 59
+ "Y", // 60
+ "Z", // 61
+ "bracketleft", // 62
+ "backslash", // 63
+ "bracketright", // 64
+ "asciicircum", // 65
+ "underscore", // 66
+ "grave", // 67
+ "a", // 68
+ "b", // 69
+ "c", // 70
+ "d", // 71
+ "e", // 72
+ "f", // 73
+ "g", // 74
+ "h", // 75
+ "i", // 76
+ "j", // 77
+ "k", // 78
+ "l", // 79
+ "m", // 80
+ "n", // 81
+ "o", // 82
+ "p", // 83
+ "q", // 84
+ "r", // 85
+ "s", // 86
+ "t", // 87
+ "u", // 88
+ "v", // 89
+ "w", // 90
+ "x", // 91
+ "y", // 92
+ "z", // 93
+ "braceleft", // 94
+ "bar", // 95
+ "braceright", // 96
+ "asciitilde", // 97
+ "Adieresis", // 98
+ "Aring", // 99
+ "Ccedilla", // 100
+ "Eacute", // 101
+ "Ntilde", // 102
+ "Odieresis", // 103
+ "Udieresis", // 104
+ "aacute", // 105
+ "agrave", // 106
+ "acircumflex", // 107
+ "adieresis", // 108
+ "atilde", // 109
+ "aring", // 110
+ "ccedilla", // 111
+ "eacute", // 112
+ "egrave", // 113
+ "ecircumflex", // 114
+ "edieresis", // 115
+ "iacute", // 116
+ "igrave", // 117
+ "icircumflex", // 118
+ "idieresis", // 119
+ "ntilde", // 120
+ "oacute", // 121
+ "ograve", // 122
+ "ocircumflex", // 123
+ "odieresis", // 124
+ "otilde", // 125
+ "uacute", // 126
+ "ugrave", // 127
+ "ucircumflex", // 128
+ "udieresis", // 129
+ "dagger", // 130
+ "degree", // 131
+ "cent", // 132
+ "sterling", // 133
+ "section", // 134
+ "bullet", // 135
+ "paragraph", // 136
+ "germandbls", // 137
+ "registered", // 138
+ "copyright", // 139
+ "trademark", // 140
+ "acute", // 141
+ "dieresis", // 142
+ "notequal", // 143
+ "AE", // 144
+ "Oslash", // 145
+ "infinity", // 146
+ "plusminus", // 147
+ "lessequal", // 148
+ "greaterequal", // 149
+ "yen", // 150
+ "mu", // 151
+ "partialdiff", // 152
+ "summation", // 153
+ "product", // 154
+ "pi", // 155
+ "integral'", // 156
+ "ordfeminine", // 157
+ "ordmasculine", // 158
+ "Omega", // 159
+ "ae", // 160
+ "oslash", // 161
+ "questiondown", // 162
+ "exclamdown", // 163
+ "logicalnot", // 164
+ "radical", // 165
+ "florin", // 166
+ "approxequal", // 167
+ "increment", // 168
+ "guillemotleft",// 169
+ "guillemotright",//170
+ "ellipsis", // 171
+ "nbspace", // 172
+ "Agrave", // 173
+ "Atilde", // 174
+ "Otilde", // 175
+ "OE", // 176
+ "oe", // 177
+ "endash", // 178
+ "emdash", // 179
+ "quotedblleft", // 180
+ "quotedblright",// 181
+ "quoteleft", // 182
+ "quoteright", // 183
+ "divide", // 184
+ "lozenge", // 185
+ "ydieresis", // 186
+ "Ydieresis", // 187
+ "fraction", // 188
+ "currency", // 189
+ "guilsinglleft",// 190
+ "guilsinglright",//191
+ "fi", // 192
+ "fl", // 193
+ "daggerdbl", // 194
+ "middot", // 195
+ "quotesinglbase",//196
+ "quotedblbase", // 197
+ "perthousand", // 198
+ "Acircumflex", // 199
+ "Ecircumflex", // 200
+ "Aacute", // 201
+ "Edieresis", // 202
+ "Egrave", // 203
+ "Iacute", // 204
+ "Icircumflex", // 205
+ "Idieresis", // 206
+ "Igrave", // 207
+ "Oacute", // 208
+ "Ocircumflex", // 209
+ "", // 210
+ "Ograve", // 211
+ "Uacute", // 212
+ "Ucircumflex", // 213
+ "Ugrave", // 214
+ "dotlessi", // 215
+ "circumflex", // 216
+ "tilde", // 217
+ "overscore", // 218
+ "breve", // 219
+ "dotaccent", // 220
+ "ring", // 221
+ "cedilla", // 222
+ "hungarumlaut", // 223
+ "ogonek", // 224
+ "caron", // 225
+ "Lslash", // 226
+ "lslash", // 227
+ "Scaron", // 228
+ "scaron", // 229
+ "Zcaron", // 230
+ "zcaron", // 231
+ "brokenbar", // 232
+ "Eth", // 233
+ "eth", // 234
+ "Yacute", // 235
+ "yacute", // 236
+ "Thorn", // 237
+ "thorn", // 238
+ "minus", // 239
+ "multiply", // 240
+ "onesuperior", // 241
+ "twosuperior", // 242
+ "threesuperior",// 243
+ "onehalf", // 244
+ "onequarter", // 245
+ "threequarters",// 246
+ "franc", // 247
+ "Gbreve", // 248
+ "gbreve", // 249
+ "Idot", // 250
+ "Scedilla", // 251
+ "scedilla", // 252
+ "Cacute", // 253
+ "cacute", // 254
+ "Ccaron", // 255
+ "ccaron", // 256
+ "" // 257
+ };
+
+ private DirectoryEntry de;
+ private int version;
+ private int italicAngle;
+ private short underlinePosition;
+ private short underlineThickness;
+ private int isFixedPitch;
+ private int minMemType42;
+ private int maxMemType42;
+ private int minMemType1;
+ private int maxMemType1;
+
+ // v2
+ private int numGlyphs;
+ private int[] glyphNameIndex;
+ private String[] psGlyphName;
+
+ /** Creates new PostTable */
+ protected PostTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ version = di.readInt();
+ italicAngle = di.readInt();
+ underlinePosition = di.readShort();
+ underlineThickness = di.readShort();
+ isFixedPitch = di.readInt();
+ minMemType42 = di.readInt();
+ maxMemType42 = di.readInt();
+ minMemType1 = di.readInt();
+ maxMemType1 = di.readInt();
+
+ if (version == 0x00020000) {
+ numGlyphs = di.readUnsignedShort();
+ glyphNameIndex = new int[numGlyphs];
+ for (int i = 0; i < numGlyphs; i++) {
+ glyphNameIndex[i] = di.readUnsignedShort();
+ }
+ int h = highestGlyphNameIndex();
+ if (h > 257) {
+ h -= 257;
+ psGlyphName = new String[h];
+ for (int i = 0; i < h; i++) {
+ int len = di.readUnsignedByte();
+ byte[] buf = new byte[len];
+ di.readFully(buf);
+ psGlyphName[i] = new String(buf);
+ }
+ }
+ } else if (version == 0x00025000) {
+ } else if (version == 0x00030000) {
+ }
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ private int highestGlyphNameIndex() {
+ int high = 0;
+ for (int i = 0; i < numGlyphs; i++) {
+ if (high < glyphNameIndex[i]) {
+ high = glyphNameIndex[i];
+ }
+ }
+ return high;
+ }
+
+ public String getGlyphName(int i) {
+ if (version == 0x00020000) {
+ return (glyphNameIndex[i] > 257)
+ ? psGlyphName[glyphNameIndex[i] - 258]
+ : macGlyphName[glyphNameIndex[i]];
+ } else {
+ return null;
+ }
+ }
+
+ private boolean isMacGlyphName(int i) {
+ if (version == 0x00020000) {
+ return glyphNameIndex[i] <= 257;
+ } else {
+ return false;
+ }
+ }
+
+ /** Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType() {
+ return post;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'post' Table - PostScript Metrics\n---------------------------------\n")
+ .append("\n 'post' version: ").append(Fixed.floatValue(version))
+ .append("\n italicAngle: ").append(Fixed.floatValue(italicAngle))
+ .append("\n underlinePosition: ").append(underlinePosition)
+ .append("\n underlineThickness: ").append(underlineThickness)
+ .append("\n isFixedPitch: ").append(isFixedPitch)
+ .append("\n minMemType42: ").append(minMemType42)
+ .append("\n maxMemType42: ").append(maxMemType42)
+ .append("\n minMemType1: ").append(minMemType1)
+ .append("\n maxMemType1: ").append(maxMemType1);
+
+ if (version == 0x00020000) {
+ sb.append("\n\n Format 2.0: Non-Standard (for PostScript) TrueType Glyph Set.\n");
+ sb.append(" numGlyphs: ").append(numGlyphs).append("\n");
+ for (int i = 0; i < numGlyphs; i++) {
+ sb.append(" Glyf ").append(i).append(" -> ");
+ if (isMacGlyphName(i)) {
+ sb.append("Mac Glyph # ").append(glyphNameIndex[i])
+ .append(", '").append(macGlyphName[glyphNameIndex[i]]).append("'\n");
+ } else {
+ sb.append("PSGlyf Name # ").append(glyphNameIndex[i] - 257)
+ .append(", name= '").append(psGlyphName[glyphNameIndex[i] - 258]).append("'\n");
+ }
+ }
+ sb.append("\n Full List of PSGlyf Names\n ------------------------\n");
+ for (int i = 0; i < psGlyphName.length; i++) {
+ sb.append(" PSGlyf Name # ").append(i + 1)
+ .append(": ").append(psGlyphName[i])
+ .append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/PrepTable.java b/src/typecast/net/java/dev/typecast/ot/table/PrepTable.java
new file mode 100644
index 000000000..938b9b840
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/PrepTable.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Disassembler;
+
+/**
+ * @version $Id: PrepTable.java,v 1.1.1.1 2004-12-05 23:14:57 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class PrepTable extends Program implements Table {
+
+ private DirectoryEntry de;
+
+ public PrepTable(DirectoryEntry de, DataInput di) throws IOException {
+ this.de = (DirectoryEntry) de.clone();
+ readInstructions(di, de.getLength());
+ }
+
+ public int getType() {
+ return prep;
+ }
+
+ public String toString() {
+ return Disassembler.disassemble(getInstructions(), 0);
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return de;
+ }
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Program.java b/src/typecast/net/java/dev/typecast/ot/table/Program.java
new file mode 100644
index 000000000..d4dd094e2
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Program.java
@@ -0,0 +1,40 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * @version $Id: Program.java,v 1.1.1.1 2004-12-05 23:14:57 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public abstract class Program {
+
+ private short[] instructions;
+
+ public short[] getInstructions() {
+ return instructions;
+ }
+
+ protected void readInstructions(DataInput di, int count) throws IOException {
+ instructions = new short[count];
+ for (int i = 0; i < count; i++) {
+ instructions[i] = (short) di.readUnsignedByte();
+ }
+ }
+/*
+ protected void readInstructions(ByteArrayInputStream bais, int count) {
+ instructions = new short[count];
+ for (int i = 0; i < count; i++) {
+ instructions[i] = (short) bais.read();
+ }
+ }
+*/
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/RangeRecord.java b/src/typecast/net/java/dev/typecast/ot/table/RangeRecord.java
new file mode 100644
index 000000000..3bcb9ccb5
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/RangeRecord.java
@@ -0,0 +1,87 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Coverage Index (GlyphID) = StartCoverageIndex + GlyphID - Start GlyphID
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: RangeRecord.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class RangeRecord {
+
+ private int _start;
+ private int _end;
+ private int _startCoverageIndex;
+
+ /** Creates new RangeRecord */
+ public RangeRecord(DataInput di) throws IOException {
+ _start = di.readUnsignedShort();
+ _end = di.readUnsignedShort();
+ _startCoverageIndex = di.readUnsignedShort();
+ }
+
+ public boolean isInRange(int glyphId) {
+ return (_start <= glyphId && glyphId <= _end);
+ }
+
+ public int getCoverageIndex(int glyphId) {
+ if (isInRange(glyphId)) {
+ return _startCoverageIndex + glyphId - _start;
+ }
+ return -1;
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Script.java b/src/typecast/net/java/dev/typecast/ot/table/Script.java
new file mode 100644
index 000000000..e3022c116
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Script.java
@@ -0,0 +1,118 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Script.java,v 1.2 2007-01-24 09:47:47 davidsch Exp $
+ */
+public class Script {
+
+ private int _defaultLangSysOffset;
+ private int _langSysCount;
+ private LangSysRecord[] _langSysRecords;
+ private LangSys _defaultLangSys;
+ private LangSys[] _langSys;
+
+ /** Creates new ScriptTable */
+ protected Script(DataInputStream dis, int offset) throws IOException {
+
+ // Ensure we're in the right place
+ dis.reset();
+ dis.skipBytes(offset);
+
+ // Start reading
+ _defaultLangSysOffset = dis.readUnsignedShort();
+ _langSysCount = dis.readUnsignedShort();
+ if (_langSysCount > 0) {
+ _langSysRecords = new LangSysRecord[_langSysCount];
+ for (int i = 0; i < _langSysCount; i++) {
+ _langSysRecords[i] = new LangSysRecord(dis);
+ }
+ }
+
+ // Read the LangSys tables
+ if (_langSysCount > 0) {
+ _langSys = new LangSys[_langSysCount];
+ for (int i = 0; i < _langSysCount; i++) {
+ dis.reset();
+ dis.skipBytes(offset + _langSysRecords[i].getOffset());
+ _langSys[i] = new LangSys(dis);
+ }
+ }
+ if (_defaultLangSysOffset > 0) {
+ dis.reset();
+ dis.skipBytes(offset + _defaultLangSysOffset);
+ _defaultLangSys = new LangSys(dis);
+ }
+ }
+
+ public int getLangSysCount() {
+ return _langSysCount;
+ }
+
+ public LangSysRecord getLangSysRecord(int i) {
+ return _langSysRecords[i];
+ }
+
+ public LangSys getDefaultLangSys() {
+ return _defaultLangSys;
+ }
+
+ public LangSys getLangSys(int i) {
+ return _langSys[i];
+ }
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ScriptList.java b/src/typecast/net/java/dev/typecast/ot/table/ScriptList.java
new file mode 100644
index 000000000..bd82a052f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ScriptList.java
@@ -0,0 +1,115 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ScriptList.java,v 1.3 2007-01-24 09:54:44 davidsch Exp $
+ */
+public class ScriptList {
+
+ private int _scriptCount = 0;
+ private ScriptRecord[] _scriptRecords;
+ private Script[] _scripts;
+
+ /** Creates new ScriptList */
+ protected ScriptList(DataInputStream dis, int offset) throws IOException {
+
+ // Ensure we're in the right place
+ dis.reset();
+ dis.skipBytes(offset);
+
+ // Start reading
+ _scriptCount = dis.readUnsignedShort();
+ _scriptRecords = new ScriptRecord[_scriptCount];
+ _scripts = new Script[_scriptCount];
+ for (int i = 0; i < _scriptCount; i++) {
+ _scriptRecords[i] = new ScriptRecord(dis);
+ }
+ for (int i = 0; i < _scriptCount; i++) {
+ _scripts[i] = new Script(dis, offset + _scriptRecords[i].getOffset());
+ }
+ }
+
+ public int getScriptCount() {
+ return _scriptCount;
+ }
+
+ public ScriptRecord getScriptRecord(int i) {
+ return _scriptRecords[i];
+ }
+
+ public Script getScript(int i) {
+ return _scripts[i];
+ }
+
+ public Script findScript(String tag) {
+ if (tag.length() != 4) {
+ return null;
+ }
+ int tagVal = ((tag.charAt(0)<<24)
+ | (tag.charAt(1)<<16)
+ | (tag.charAt(2)<<8)
+ | tag.charAt(3));
+ for (int i = 0; i < _scriptCount; i++) {
+ if (_scriptRecords[i].getTag() == tagVal) {
+ return _scripts[i];
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ScriptRecord.java b/src/typecast/net/java/dev/typecast/ot/table/ScriptRecord.java
new file mode 100644
index 000000000..aea0bf0df
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ScriptRecord.java
@@ -0,0 +1,88 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: ScriptRecord.java,v 1.2 2007-01-24 09:47:46 davidsch Exp $
+ */
+public class ScriptRecord {
+
+ private int _tag;
+ private int _offset;
+
+ /** Creates new ScriptRecord */
+ protected ScriptRecord(DataInput di) throws IOException {
+ _tag = di.readInt();
+ _offset = di.readUnsignedShort();
+ }
+
+ public int getTag() {
+ return _tag;
+ }
+
+ public int getOffset() {
+ return _offset;
+ }
+
+ public String getTagAsString() {
+ return new StringBuffer()
+ .append((char)((_tag>>24)&0xff))
+ .append((char)((_tag>>16)&0xff))
+ .append((char)((_tag>>8)&0xff))
+ .append((char)((_tag)&0xff))
+ .toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/ScriptTags.java b/src/typecast/net/java/dev/typecast/ot/table/ScriptTags.java
new file mode 100644
index 000000000..eeb4f8e25
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/ScriptTags.java
@@ -0,0 +1,61 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * Definition of Script tags
+ *
+ * @version $Id: ScriptTags.java,v 1.2 2007-01-24 09:47:46 davidsch Exp $
+ * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
+ */
+public interface ScriptTags {
+ public static final String SCRIPT_TAG_ARAB = "arab";
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/SignatureBlock.java b/src/typecast/net/java/dev/typecast/ot/table/SignatureBlock.java
new file mode 100644
index 000000000..2e4acf525
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/SignatureBlock.java
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.IOException;
+import java.io.DataInput;
+
+/**
+ *
+ * @version $Id: SignatureBlock.java,v 1.1.1.1 2004-12-05 23:14:58 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class SignatureBlock {
+
+ private int reserved1;
+ private int reserved2;
+ private int signatureLen;
+ private byte[] signature;
+
+ /** Creates new SignatureBlock */
+ protected SignatureBlock(DataInput di) throws IOException {
+ reserved1 = di.readUnsignedShort();
+ reserved2 = di.readUnsignedShort();
+ signatureLen = di.readInt();
+ signature = new byte[signatureLen];
+ di.readFully(signature);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < signatureLen; i += 16) {
+ if (signatureLen - i >= 16) {
+ sb.append(new String(signature, i, 16)).append("\n");
+ } else {
+ sb.append(new String(signature, i, signatureLen - i)).append("\n");
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/SingleSubst.java b/src/typecast/net/java/dev/typecast/ot/table/SingleSubst.java
new file mode 100644
index 000000000..91c985883
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/SingleSubst.java
@@ -0,0 +1,81 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: SingleSubst.java,v 1.2 2007-01-24 09:47:46 davidsch Exp $
+ */
+public abstract class SingleSubst extends LookupSubtable {
+
+ public abstract int getFormat();
+
+ public abstract int substitute(int glyphId);
+
+ public static SingleSubst read(DataInputStream dis, int offset) throws IOException {
+ SingleSubst s = null;
+ dis.reset();
+ dis.skipBytes(offset);
+ int format = dis.readUnsignedShort();
+ if (format == 1) {
+ s = new SingleSubstFormat1(dis, offset);
+ } else if (format == 2) {
+ s = new SingleSubstFormat2(dis, offset);
+ }
+ return s;
+ }
+
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat1.java b/src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat1.java
new file mode 100644
index 000000000..538c57f6d
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat1.java
@@ -0,0 +1,92 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: SingleSubstFormat1.java,v 1.2 2007-01-24 09:47:45 davidsch Exp $
+ */
+public class SingleSubstFormat1 extends SingleSubst {
+
+ private int _coverageOffset;
+ private short _deltaGlyphID;
+ private Coverage _coverage;
+
+ /** Creates new SingleSubstFormat1 */
+ protected SingleSubstFormat1(DataInputStream dis, int offset) throws IOException {
+ _coverageOffset = dis.readUnsignedShort();
+ _deltaGlyphID = dis.readShort();
+ dis.reset();
+ dis.skipBytes(offset + _coverageOffset);
+ _coverage = Coverage.read(dis);
+ }
+
+ public int getFormat() {
+ return 1;
+ }
+
+ public int substitute(int glyphId) {
+ int i = _coverage.findGlyph(glyphId);
+ if (i > -1) {
+ return glyphId + _deltaGlyphID;
+ }
+ return glyphId;
+ }
+
+ public String getTypeAsString() {
+ return "SingleSubstFormat1";
+ }
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat2.java b/src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat2.java
new file mode 100644
index 000000000..74c68f71f
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/SingleSubstFormat2.java
@@ -0,0 +1,97 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: SingleSubstFormat2.java,v 1.2 2007-01-24 09:47:48 davidsch Exp $
+ */
+public class SingleSubstFormat2 extends SingleSubst {
+
+ private int _coverageOffset;
+ private int _glyphCount;
+ private int[] _substitutes;
+ private Coverage _coverage;
+
+ /** Creates new SingleSubstFormat2 */
+ protected SingleSubstFormat2(DataInputStream dis, int offset) throws IOException {
+ _coverageOffset = dis.readUnsignedShort();
+ _glyphCount = dis.readUnsignedShort();
+ _substitutes = new int[_glyphCount];
+ for (int i = 0; i < _glyphCount; i++) {
+ _substitutes[i] = dis.readUnsignedShort();
+ }
+ dis.reset();
+ dis.skipBytes(offset + _coverageOffset);
+ _coverage = Coverage.read(dis);
+ }
+
+ public int getFormat() {
+ return 2;
+ }
+
+ public int substitute(int glyphId) {
+ int i = _coverage.findGlyph(glyphId);
+ if (i > -1) {
+ return _substitutes[i];
+ }
+ return glyphId;
+ }
+
+ public String getTypeAsString() {
+ return "SingleSubstFormat2";
+ }
+}
+
diff --git a/src/typecast/net/java/dev/typecast/ot/table/TTCHeader.java b/src/typecast/net/java/dev/typecast/ot/table/TTCHeader.java
new file mode 100644
index 000000000..2f38d33f4
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/TTCHeader.java
@@ -0,0 +1,59 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ *
+ * @version $Id: TTCHeader.java,v 1.1.1.1 2004-12-05 23:15:01 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class TTCHeader {
+
+ public static final int ttcf = 0x74746366;
+
+ private int ttcTag;
+ private int version;
+ private int directoryCount;
+ private int[] tableDirectory;
+ private int dsigTag;
+ private int dsigLength;
+ private int dsigOffset;
+
+ /** Creates new TTCHeader */
+ public TTCHeader(DataInput di) throws IOException {
+ ttcTag = di.readInt();
+ version = di.readInt();
+ directoryCount = di.readInt();
+ tableDirectory = new int[directoryCount];
+ for (int i = 0; i < directoryCount; i++) {
+ tableDirectory[i] = di.readInt();
+ }
+ if (version == 0x00010000) {
+ dsigTag = di.readInt();
+ }
+ dsigLength = di.readInt();
+ dsigOffset = di.readInt();
+ }
+
+ public int getDirectoryCount() {
+ return directoryCount;
+ }
+
+ public int getTableDirectory(int i) {
+ return tableDirectory[i];
+ }
+
+ public static boolean isTTC(DataInput di) throws IOException {
+ int ttcTag = di.readInt();
+ return ttcTag == ttcf;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/Table.java b/src/typecast/net/java/dev/typecast/ot/table/Table.java
new file mode 100644
index 000000000..ddbdc49e2
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/Table.java
@@ -0,0 +1,67 @@
+/*****************************************************************************
+ * Copyright (C) The Apache Software Foundation. All rights reserved. *
+ * ------------------------------------------------------------------------- *
+ * This software is published under the terms of the Apache Software License *
+ * version 1.1, a copy of which has been included with this distribution in *
+ * the LICENSE file. *
+ *****************************************************************************/
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ * @version $Id: Table.java,v 1.1.1.1 2004-12-05 23:14:59 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public interface Table {
+
+ // Table constants
+ public static final int BASE = 0x42415345; // Baseline data [OpenType]
+ public static final int CFF = 0x43464620; // PostScript font program (compact font format) [PostScript]
+ public static final int DSIG = 0x44534947; // Digital signature
+ public static final int EBDT = 0x45424454; // Embedded bitmap data
+ public static final int EBLC = 0x45424c43; // Embedded bitmap location data
+ public static final int EBSC = 0x45425343; // Embedded bitmap scaling data
+ public static final int GDEF = 0x47444546; // Glyph definition data [OpenType]
+ public static final int GPOS = 0x47504f53; // Glyph positioning data [OpenType]
+ public static final int GSUB = 0x47535542; // Glyph substitution data [OpenType]
+ public static final int JSTF = 0x4a535446; // Justification data [OpenType]
+ public static final int LTSH = 0x4c545348; // Linear threshold table
+ public static final int MMFX = 0x4d4d4658; // Multiple master font metrics [PostScript]
+ public static final int MMSD = 0x4d4d5344; // Multiple master supplementary data [PostScript]
+ public static final int OS_2 = 0x4f532f32; // OS/2 and Windows specific metrics [r]
+ public static final int PCLT = 0x50434c54; // PCL5
+ public static final int VDMX = 0x56444d58; // Vertical Device Metrics table
+ public static final int cmap = 0x636d6170; // character to glyph mapping [r]
+ public static final int cvt = 0x63767420; // Control Value Table
+ public static final int fpgm = 0x6670676d; // font program
+ public static final int fvar = 0x66766172; // Apple's font variations table [PostScript]
+ public static final int gasp = 0x67617370; // grid-fitting and scan conversion procedure (grayscale)
+ public static final int glyf = 0x676c7966; // glyph data [r]
+ public static final int hdmx = 0x68646d78; // horizontal device metrics
+ public static final int head = 0x68656164; // font header [r]
+ public static final int hhea = 0x68686561; // horizontal header [r]
+ public static final int hmtx = 0x686d7478; // horizontal metrics [r]
+ public static final int kern = 0x6b65726e; // kerning
+ public static final int loca = 0x6c6f6361; // index to location [r]
+ public static final int maxp = 0x6d617870; // maximum profile [r]
+ public static final int name = 0x6e616d65; // naming table [r]
+ public static final int prep = 0x70726570; // CVT Program
+ public static final int post = 0x706f7374; // PostScript information [r]
+ public static final int vhea = 0x76686561; // Vertical Metrics header
+ public static final int vmtx = 0x766d7478; // Vertical Metrics
+
+ /**
+ * Get the table type, as a table directory value.
+ * @return The table type
+ */
+ public int getType();
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry();
+
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/TableDirectory.java b/src/typecast/net/java/dev/typecast/ot/table/TableDirectory.java
new file mode 100644
index 000000000..2eff53dd9
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/TableDirectory.java
@@ -0,0 +1,129 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Fixed;
+
+/**
+ * @version $Id: TableDirectory.java,v 1.2 2004-12-09 23:46:21 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class TableDirectory {
+
+ private int _version = 0;
+ private short _numTables = 0;
+ private short _searchRange = 0;
+ private short _entrySelector = 0;
+ private short _rangeShift = 0;
+ private DirectoryEntry[] _entries;
+
+ public TableDirectory(DataInput di) throws IOException {
+ _version = di.readInt();
+ _numTables = di.readShort();
+ _searchRange = di.readShort();
+ _entrySelector = di.readShort();
+ _rangeShift = di.readShort();
+ _entries = new DirectoryEntry[_numTables];
+ for (int i = 0; i < _numTables; i++) {
+ _entries[i] = new DirectoryEntry(di);
+ }
+ }
+
+ public DirectoryEntry getEntry(int index) {
+ return _entries[index];
+ }
+
+ public DirectoryEntry getEntryByTag(int tag) {
+ for (int i = 0; i < _numTables; i++) {
+ if (_entries[i].getTag() == tag) {
+ return _entries[i];
+ }
+ }
+ return null;
+ }
+
+ public short getEntrySelector() {
+ return _entrySelector;
+ }
+
+ public short getNumTables() {
+ return _numTables;
+ }
+
+ public short getRangeShift() {
+ return _rangeShift;
+ }
+
+ public short getSearchRange() {
+ return _searchRange;
+ }
+
+ public int getVersion() {
+ return _version;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer()
+ .append("Offset Table\n------ -----")
+ .append("\n sfnt version: ").append(Fixed.floatValue(_version))
+ .append("\n numTables = ").append(_numTables)
+ .append("\n searchRange = ").append(_searchRange)
+ .append("\n entrySelector = ").append(_entrySelector)
+ .append("\n rangeShift = ").append(_rangeShift)
+ .append("\n\n");
+ for (int i = 0; i < _numTables; i++) {
+ sb.append(i).append(". ").append(_entries[i].toString()).append("\n");
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/TableException.java b/src/typecast/net/java/dev/typecast/ot/table/TableException.java
new file mode 100644
index 000000000..02bc49eb5
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/TableException.java
@@ -0,0 +1,46 @@
+/*
+ * $Id: TableException.java,v 1.1.1.1 2004-12-05 23:15:00 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+/**
+ *
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: TableException.java,v 1.1.1.1 2004-12-05 23:15:00 davidsch Exp $
+ */
+public class TableException extends java.lang.Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Creates a new instance of <code>TableException</code> without detail message.
+ */
+ public TableException() {
+ }
+
+
+ /**
+ * Constructs an instance of <code>TableException</code> with the specified detail message.
+ * @param msg the detail message.
+ */
+ public TableException(String msg) {
+ super(msg);
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/TableFactory.java b/src/typecast/net/java/dev/typecast/ot/table/TableFactory.java
new file mode 100644
index 000000000..28a7a4a97
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/TableFactory.java
@@ -0,0 +1,184 @@
+/*
+
+ ============================================================================
+ The Apache Software License, Version 1.1
+ ============================================================================
+
+ Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modifica-
+ tion, 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.
+
+ 3. The end-user documentation included with the redistribution, if any, must
+ include the following acknowledgment: "This product includes software
+ developed by the Apache Software Foundation (http://www.apache.org/)."
+ Alternately, this acknowledgment may appear in the software itself, if
+ and wherever such third-party acknowledgments normally appear.
+
+ 4. The names "Batik" and "Apache Software Foundation" must not be
+ used to endorse or promote products derived from this software without
+ prior written permission. For written permission, please contact
+ apache@apache.org.
+
+ 5. Products derived from this software may not be called "Apache", nor may
+ "Apache" appear in their name, without prior written permission of the
+ Apache Software Foundation.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 THE
+ APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ DING, 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.
+
+ This software consists of voluntary contributions made by many individuals
+ on behalf of the Apache Software Foundation. For more information on the
+ Apache Software Foundation, please see <http://www.apache.org/>.
+
+*/
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import net.java.dev.typecast.ot.OTFont;
+import net.java.dev.typecast.ot.OTFontCollection;
+
+/**
+ *
+ * @version $Id: TableFactory.java,v 1.7 2007-02-05 12:39:51 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class TableFactory {
+
+ public static Table create(
+ OTFontCollection fc,
+ OTFont font,
+ DirectoryEntry de,
+ DataInputStream dis) throws IOException {
+ Table t = null;
+
+ // First, if we have a font collection, look for the table there
+ if (fc != null) {
+ t = fc.getTable(de);
+ if (t != null) {
+ return t;
+ }
+ }
+
+ // Create the table
+ switch (de.getTag()) {
+ case Table.BASE:
+ t = new BaseTable(de, dis);
+ break;
+ case Table.CFF:
+ t = new CffTable(de, dis);
+ break;
+ case Table.DSIG:
+ t = new DsigTable(de, dis);
+ break;
+ case Table.EBDT:
+ break;
+ case Table.EBLC:
+ break;
+ case Table.EBSC:
+ break;
+ case Table.GDEF:
+ break;
+ case Table.GPOS:
+ t = new GposTable(de, dis);
+ break;
+ case Table.GSUB:
+ t = new GsubTable(de, dis);
+ break;
+ case Table.JSTF:
+ break;
+ case Table.LTSH:
+ t = new LtshTable(de, dis);
+ break;
+ case Table.MMFX:
+ break;
+ case Table.MMSD:
+ break;
+ case Table.OS_2:
+ t = new Os2Table(de, dis);
+ break;
+ case Table.PCLT:
+ t = new PcltTable(de, dis);
+ break;
+ case Table.VDMX:
+ t = new VdmxTable(de, dis);
+ break;
+ case Table.cmap:
+ t = new CmapTable(de, dis);
+ break;
+ case Table.cvt:
+ t = new CvtTable(de, dis);
+ break;
+ case Table.fpgm:
+ t = new FpgmTable(de, dis);
+ break;
+ case Table.fvar:
+ break;
+ case Table.gasp:
+ t = new GaspTable(de, dis);
+ break;
+ case Table.glyf:
+ t = new GlyfTable(de, dis, font.getMaxpTable(), font.getLocaTable());
+ break;
+ case Table.hdmx:
+ t = new HdmxTable(de, dis, font.getMaxpTable());
+ break;
+ case Table.head:
+ t = new HeadTable(de, dis);
+ break;
+ case Table.hhea:
+ t = new HheaTable(de, dis);
+ break;
+ case Table.hmtx:
+ t = new HmtxTable(de, dis, font.getHheaTable(), font.getMaxpTable());
+ break;
+ case Table.kern:
+ t = new KernTable(de, dis);
+ break;
+ case Table.loca:
+ t = new LocaTable(de, dis, font.getHeadTable(), font.getMaxpTable());
+ break;
+ case Table.maxp:
+ t = new MaxpTable(de, dis);
+ break;
+ case Table.name:
+ t = new NameTable(de, dis);
+ break;
+ case Table.prep:
+ t = new PrepTable(de, dis);
+ break;
+ case Table.post:
+ t = new PostTable(de, dis);
+ break;
+ case Table.vhea:
+ t = new VheaTable(de, dis);
+ break;
+ case Table.vmtx:
+ t = new VmtxTable(de, dis, font.getVheaTable(), font.getMaxpTable());
+ break;
+ }
+
+ // If we have a font collection, add this table to it
+ if ((fc != null) && (t != null)) {
+ fc.addTable(t);
+ }
+ return t;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/VdmxTable.java b/src/typecast/net/java/dev/typecast/ot/table/VdmxTable.java
new file mode 100644
index 000000000..907133b6d
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/VdmxTable.java
@@ -0,0 +1,197 @@
+/*
+ * $Id: VdmxTable.java,v 1.1 2007-01-30 05:25:35 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * The Vertical Device Metrics table for TrueType outlines.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: VdmxTable.java,v 1.1 2007-01-30 05:25:35 davidsch Exp $
+ */
+public class VdmxTable implements Table {
+
+ private class Ratio {
+
+ private byte _bCharSet;
+ private byte _xRatio;
+ private byte _yStartRatio;
+ private byte _yEndRatio;
+
+ protected Ratio(DataInput di) throws IOException {
+ _bCharSet = di.readByte();
+ _xRatio = di.readByte();
+ _yStartRatio = di.readByte();
+ _yEndRatio = di.readByte();
+ }
+
+ public byte getBCharSet() {
+ return _bCharSet;
+ }
+
+ public byte getXRatio() {
+ return _xRatio;
+ }
+
+ public byte getYStartRatio() {
+ return _yStartRatio;
+ }
+
+ public byte getYEndRatio() {
+ return _yEndRatio;
+ }
+ }
+
+ private class VTableRecord {
+
+ private int _yPelHeight;
+ private short _yMax;
+ private short _yMin;
+
+ protected VTableRecord(DataInput di) throws IOException {
+ _yPelHeight = di.readUnsignedShort();
+ _yMax = di.readShort();
+ _yMin = di.readShort();
+ }
+
+ public int getYPelHeight() {
+ return _yPelHeight;
+ }
+
+ public short getYMax() {
+ return _yMax;
+ }
+
+ public short getYMin() {
+ return _yMin;
+ }
+ }
+
+ private class Group {
+
+ private int _recs;
+ private int _startsz;
+ private int _endsz;
+ private VTableRecord[] _entry;
+
+ protected Group(DataInput di) throws IOException {
+ _recs = di.readUnsignedShort();
+ _startsz = di.readUnsignedByte();
+ _endsz = di.readUnsignedByte();
+ _entry = new VTableRecord[_recs];
+ for (int i = 0; i < _recs; ++i) {
+ _entry[i] = new VTableRecord(di);
+ }
+ }
+
+ public int getRecs() {
+ return _recs;
+ }
+
+ public int getStartSZ() {
+ return _startsz;
+ }
+
+ public int getEndSZ() {
+ return _endsz;
+ }
+
+ public VTableRecord[] getEntry() {
+ return _entry;
+ }
+ }
+
+ private DirectoryEntry _de;
+ private int _version;
+ private int _numRecs;
+ private int _numRatios;
+ private Ratio[] _ratRange;
+ private int _offset[];
+ private Group[] _groups;
+
+ /** Creates a new instance of VdmxTable */
+ protected VdmxTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _version = di.readUnsignedShort();
+ _numRecs = di.readUnsignedShort();
+ _numRatios = di.readUnsignedShort();
+ _ratRange = new Ratio[_numRatios];
+ for (int i = 0; i < _numRatios; ++i) {
+ _ratRange[i] = new Ratio(di);
+ }
+ _offset = new int[_numRatios];
+ for (int i = 0; i < _numRatios; ++i) {
+ _offset[i] = di.readUnsignedShort();
+ }
+ _groups = new Group[_numRecs];
+ for (int i = 0; i < _numRecs; ++i) {
+ _groups[i] = new Group(di);
+ }
+ }
+
+ public int getType() {
+ return VDMX;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'VDMX' Table - Precomputed Vertical Device Metrics\n")
+ .append("--------------------------------------------------\n")
+ .append(" Version: ").append(_version).append("\n")
+ .append(" Number of Hgt Records: ").append(_numRecs).append("\n")
+ .append(" Number of Ratio Records: ").append(_numRatios).append("\n");
+ for (int i = 0; i < _numRatios; ++i) {
+ sb.append("\n Ratio Record #").append(i + 1).append("\n")
+ .append("\tCharSetId ").append(_ratRange[i].getBCharSet()).append("\n")
+ .append("\txRatio ").append(_ratRange[i].getXRatio()).append("\n")
+ .append("\tyStartRatio ").append(_ratRange[i].getYStartRatio()).append("\n")
+ .append("\tyEndRatio ").append(_ratRange[i].getYEndRatio()).append("\n")
+ .append("\tRecord Offset ").append(_offset[i]).append("\n");
+ }
+ sb.append("\n VDMX Height Record Groups\n")
+ .append(" -------------------------\n");
+ for (int i = 0; i < _numRecs; ++i) {
+ Group group = _groups[i];
+ sb.append(" ").append(i + 1)
+ .append(". Number of Hgt Records ").append(group.getRecs()).append("\n")
+ .append(" Starting Y Pel Height ").append(group.getStartSZ()).append("\n")
+ .append(" Ending Y Pel Height ").append(group.getEndSZ()).append("\n");
+ for (int j = 0; j < group.getRecs(); ++j) {
+ sb.append("\n ").append(j + 1)
+ .append(". Pel Height= ").append(group.getEntry()[j].getYPelHeight()).append("\n")
+ .append(" yMax= ").append(group.getEntry()[j].getYMax()).append("\n")
+ .append(" yMin= ").append(group.getEntry()[j].getYMin()).append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/VheaTable.java b/src/typecast/net/java/dev/typecast/ot/table/VheaTable.java
new file mode 100644
index 000000000..3863080cf
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/VheaTable.java
@@ -0,0 +1,147 @@
+/*
+ * $Id: VheaTable.java,v 1.1 2007-01-31 01:17:40 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+import net.java.dev.typecast.ot.Fixed;
+
+/**
+ * Vertical Header Table
+ * @version $Id: VheaTable.java,v 1.1 2007-01-31 01:17:40 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class VheaTable implements Table {
+
+ private DirectoryEntry _de;
+ private int _version;
+ private short _ascent;
+ private short _descent;
+ private short _lineGap;
+ private short _advanceHeightMax;
+ private short _minTopSideBearing;
+ private short _minBottomSideBearing;
+ private short _yMaxExtent;
+ private short _caretSlopeRise;
+ private short _caretSlopeRun;
+ private short _metricDataFormat;
+ private int _numberOfLongVerMetrics;
+
+ protected VheaTable(DirectoryEntry de, DataInput di) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _version = di.readInt();
+ _ascent = di.readShort();
+ _descent = di.readShort();
+ _lineGap = di.readShort();
+ _advanceHeightMax = di.readShort();
+ _minTopSideBearing = di.readShort();
+ _minBottomSideBearing = di.readShort();
+ _yMaxExtent = di.readShort();
+ _caretSlopeRise = di.readShort();
+ _caretSlopeRun = di.readShort();
+ for (int i = 0; i < 5; ++i) {
+ di.readShort();
+ }
+ _metricDataFormat = di.readShort();
+ _numberOfLongVerMetrics = di.readUnsignedShort();
+ }
+
+ public short getAdvanceHeightMax() {
+ return _advanceHeightMax;
+ }
+
+ public short getAscent() {
+ return _ascent;
+ }
+
+ public short getCaretSlopeRise() {
+ return _caretSlopeRise;
+ }
+
+ public short getCaretSlopeRun() {
+ return _caretSlopeRun;
+ }
+
+ public short getDescent() {
+ return _descent;
+ }
+
+ public short getLineGap() {
+ return _lineGap;
+ }
+
+ public short getMetricDataFormat() {
+ return _metricDataFormat;
+ }
+
+ public short getMinTopSideBearing() {
+ return _minTopSideBearing;
+ }
+
+ public short getMinBottomSideBearing() {
+ return _minBottomSideBearing;
+ }
+
+ public int getNumberOfLongVerMetrics() {
+ return _numberOfLongVerMetrics;
+ }
+
+ public int getType() {
+ return vhea;
+ }
+
+ public short getYMaxExtent() {
+ return _yMaxExtent;
+ }
+
+ public String toString() {
+ return new StringBuffer()
+ .append("'vhea' Table - Vertical Header\n------------------------------")
+ .append("\n 'vhea' version: ").append(Fixed.floatValue(_version))
+ .append("\n xAscender: ").append(_ascent)
+ .append("\n xDescender: ").append(_descent)
+ .append("\n xLineGap: ").append(_lineGap)
+ .append("\n advanceHeightMax: ").append(_advanceHeightMax)
+ .append("\n minTopSideBearing: ").append(_minTopSideBearing)
+ .append("\n minBottomSideBearing: ").append(_minBottomSideBearing)
+ .append("\n yMaxExtent: ").append(_yMaxExtent)
+ .append("\n horizCaretSlopeNum: ").append(_caretSlopeRise)
+ .append("\n horizCaretSlopeDenom: ").append(_caretSlopeRun)
+ .append("\n reserved0: 0")
+ .append("\n reserved1: 0")
+ .append("\n reserved2: 0")
+ .append("\n reserved3: 0")
+ .append("\n reserved4: 0")
+ .append("\n metricDataFormat: ").append(_metricDataFormat)
+ .append("\n numOf_LongVerMetrics: ").append(_numberOfLongVerMetrics)
+ .toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/ot/table/VmtxTable.java b/src/typecast/net/java/dev/typecast/ot/table/VmtxTable.java
new file mode 100644
index 000000000..b2d9a3c3e
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/ot/table/VmtxTable.java
@@ -0,0 +1,112 @@
+/*
+ * $Id: VmtxTable.java,v 1.1 2007-01-31 01:18:04 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.ot.table;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Vertical Metrics Table
+ * @version $Id: VmtxTable.java,v 1.1 2007-01-31 01:18:04 davidsch Exp $
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ */
+public class VmtxTable implements Table {
+
+ private DirectoryEntry _de;
+ private int[] _vMetrics = null;
+ private short[] _topSideBearing = null;
+
+ protected VmtxTable(
+ DirectoryEntry de,
+ DataInput di,
+ VheaTable vhea,
+ MaxpTable maxp) throws IOException {
+ _de = (DirectoryEntry) de.clone();
+ _vMetrics = new int[vhea.getNumberOfLongVerMetrics()];
+ for (int i = 0; i < vhea.getNumberOfLongVerMetrics(); ++i) {
+ _vMetrics[i] =
+ di.readUnsignedByte()<<24
+ | di.readUnsignedByte()<<16
+ | di.readUnsignedByte()<<8
+ | di.readUnsignedByte();
+ }
+ int tsbCount = maxp.getNumGlyphs() - vhea.getNumberOfLongVerMetrics();
+ _topSideBearing = new short[tsbCount];
+ for (int i = 0; i < tsbCount; ++i) {
+ _topSideBearing[i] = di.readShort();
+ }
+ }
+
+ public int getAdvanceHeight(int i) {
+ if (_vMetrics == null) {
+ return 0;
+ }
+ if (i < _vMetrics.length) {
+ return _vMetrics[i] >> 16;
+ } else {
+ return _vMetrics[_vMetrics.length - 1] >> 16;
+ }
+ }
+
+ public short getTopSideBearing(int i) {
+ if (_vMetrics == null) {
+ return 0;
+ }
+ if (i < _vMetrics.length) {
+ return (short)(_vMetrics[i] & 0xffff);
+ } else {
+ return _topSideBearing[i - _vMetrics.length];
+ }
+ }
+
+ public int getType() {
+ return vmtx;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("'vmtx' Table - Vertical Metrics\n-------------------------------\n");
+ sb.append("Size = ").append(_de.getLength()).append(" bytes, ")
+ .append(_vMetrics.length).append(" entries\n");
+ for (int i = 0; i < _vMetrics.length; i++) {
+ sb.append(" ").append(i)
+ .append(". advHeight: ").append(getAdvanceHeight(i))
+ .append(", TSdBear: ").append(getTopSideBearing(i))
+ .append("\n");
+ }
+ for (int i = 0; i < _topSideBearing.length; i++) {
+ sb.append(" TSdBear ").append(i + _vMetrics.length)
+ .append(": ").append(_topSideBearing[i])
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a directory entry for this table. This uniquely identifies the
+ * table in collections where there may be more than one instance of a
+ * particular table.
+ * @return A directory entry
+ */
+ public DirectoryEntry getDirectoryEntry() {
+ return _de;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/t2/T2Interpreter.java b/src/typecast/net/java/dev/typecast/t2/T2Interpreter.java
new file mode 100644
index 000000000..6ae59cf8d
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/t2/T2Interpreter.java
@@ -0,0 +1,1043 @@
+/*
+ * $Id: T2Interpreter.java,v 1.2 2007-07-26 11:10:18 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.t2;
+
+import java.util.ArrayList;
+
+import net.java.dev.typecast.ot.Point;
+
+import net.java.dev.typecast.ot.table.CharstringType2;
+
+/**
+ * Type 2 Charstring Interpreter. Operator descriptions are quoted from
+ * Adobe's Type 2 Charstring Format document -- 5117.Type2.pdf.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: T2Interpreter.java,v 1.2 2007-07-26 11:10:18 davidsch Exp $
+ */
+public class T2Interpreter {
+
+ private static final int ARGUMENT_STACK_LIMIT = 48;
+ 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 int _argStackIndex = 0;
+ private int[] _subrStack = new int[SUBR_STACK_LIMIT];
+ private int _subrStackIndex = 0;
+ private Number[] _transientArray = new Number[TRANSIENT_ARRAY_ELEMENT_COUNT];
+
+ private ArrayList<Point> _points;
+
+ /** Creates a new instance of T2Interpreter */
+ public T2Interpreter() {
+ }
+
+ /**
+ * Moves the current point to a position at the relative coordinates
+ * (dx1, dy1).
+ */
+ private void _rmoveto() {
+ int dy1 = popArg().intValue();
+ int dx1 = popArg().intValue();
+ clearArg();
+ Point lastPoint = getLastPoint();
+ moveTo(lastPoint.x + dx1, lastPoint.y + dy1);
+ }
+
+ /**
+ * Moves the current point dx1 units in the horizontal direction.
+ */
+ private void _hmoveto() {
+ int dx1 = popArg().intValue();
+ clearArg();
+ Point lastPoint = getLastPoint();
+ moveTo(lastPoint.x + dx1, lastPoint.y);
+ }
+
+ /**
+ * Moves the current point dy1 units in the vertical direction.
+ */
+ private void _vmoveto() {
+ int dy1 = popArg().intValue();
+ clearArg();
+ Point lastPoint = getLastPoint();
+ moveTo(lastPoint.x, lastPoint.y + dy1);
+ }
+
+ /**
+ * Appends a line from the current point to a position at the
+ * relative coordinates dxa, dya. Additional rlineto operations are
+ * performed for all subsequent argument pairs. The number of
+ * lines is determined from the number of arguments on the stack.
+ */
+ private void _rlineto() {
+ int count = getArgCount() / 2;
+ int[] dx = new int[count];
+ int[] dy = new int[count];
+ for (int i = 0; i < count; ++i) {
+ dy[count - i - 1] = popArg().intValue();
+ dx[count - i - 1] = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ lineTo(lastPoint.x + dx[i], lastPoint.y + dy[i]);
+ }
+ clearArg();
+ }
+
+ /**
+ * Appends a horizontal line of length dx1 to the current point.
+ * With an odd number of arguments, subsequent argument pairs
+ * are interpreted as alternating values of dy and dx, for which
+ * additional lineto operators draw alternating vertical and
+ * horizontal lines. With an even number of arguments, the
+ * arguments are interpreted as alternating horizontal and
+ * vertical lines. The number of lines is determined from the
+ * number of arguments on the stack.
+ */
+ private void _hlineto() {
+ int count = getArgCount();
+ Number[] nums = new Number[count];
+ for (int i = 0; i < count; ++i) {
+ nums[count - i - 1] = popArg();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ if (i % 2 == 0) {
+ lineTo(lastPoint.x + nums[i].intValue(), lastPoint.y);
+ } else {
+ lineTo(lastPoint.x, lastPoint.y + nums[i].intValue());
+ }
+ }
+ clearArg();
+ }
+
+ /**
+ * Appends a vertical line of length dy1 to the current point. With
+ * an odd number of arguments, subsequent argument pairs are
+ * interpreted as alternating values of dx and dy, for which
+ * additional lineto operators draw alternating horizontal and
+ * vertical lines. With an even number of arguments, the
+ * arguments are interpreted as alternating vertical and
+ * horizontal lines. The number of lines is determined from the
+ * number of arguments on the stack.
+ */
+ private void _vlineto() {
+ int count = getArgCount();
+ Number[] nums = new Number[count];
+ for (int i = 0; i < count; ++i) {
+ nums[count - i - 1] = popArg();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ if (i % 2 == 0) {
+ lineTo(lastPoint.x, lastPoint.y + nums[i].intValue());
+ } else {
+ lineTo(lastPoint.x + nums[i].intValue(), lastPoint.y);
+ }
+ }
+ clearArg();
+ }
+
+ /**
+ * Appends a Bezier curve, defined by dxa...dyc, to the current
+ * point. For each subsequent set of six arguments, an additional
+ * curve is appended to the current point. The number of curve
+ * segments is determined from the number of arguments on the
+ * number stack and is limited only by the size of the number
+ * stack.
+ */
+ private void _rrcurveto() {
+ int count = getArgCount() / 6;
+ int[] dxa = new int[count];
+ int[] dya = new int[count];
+ int[] dxb = new int[count];
+ int[] dyb = new int[count];
+ int[] dxc = new int[count];
+ int[] dyc = new int[count];
+ for (int i = 0; i < count; ++i) {
+ dyc[count - i - 1] = popArg().intValue();
+ dxc[count - i - 1] = popArg().intValue();
+ dyb[count - i - 1] = popArg().intValue();
+ dxb[count - i - 1] = popArg().intValue();
+ dya[count - i - 1] = popArg().intValue();
+ dxa[count - i - 1] = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ int xa = lastPoint.x + dxa[i];
+ int ya = lastPoint.y + dya[i];
+ int xb = xa + dxb[i];
+ int yb = ya + dyb[i];
+ int xc = xb + dxc[i];
+ int yc = yb + dyc[i];
+ curveTo(xa, ya, xb, yb, xc, yc);
+ }
+ clearArg();
+ }
+
+ /**
+ * Appends one or more Bezier curves, as described by the
+ * dxa...dxc set of arguments, to the current point. For each curve,
+ * if there are 4 arguments, the curve starts and ends horizontal.
+ * The first curve need not start horizontal (the odd argument
+ * case). Note the argument order for the odd argument case.
+ */
+ private void _hhcurveto() {
+ int count = getArgCount() / 4;
+ int dy1 = 0;
+ int[] dxa = new int[count];
+ int[] dxb = new int[count];
+ int[] dyb = new int[count];
+ int[] dxc = new int[count];
+ for (int i = 0; i < count; ++i) {
+ dxc[count - i - 1] = popArg().intValue();
+ dyb[count - i - 1] = popArg().intValue();
+ dxb[count - i - 1] = popArg().intValue();
+ dxa[count - i - 1] = popArg().intValue();
+ }
+ if (getArgCount() == 1) {
+ dy1 = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ int xa = lastPoint.x + dxa[i];
+ int ya = lastPoint.y + (i == 0 ? dy1 : 0);
+ int xb = xa + dxb[i];
+ int yb = ya + dyb[i];
+ int xc = xb + dxc[i];
+ int yc = yb;
+ curveTo(xa, ya, xb, yb, xc, yc);
+ }
+ clearArg();
+ }
+
+ /**
+ * Appends one or more Bezier curves to the current point. The
+ * tangent for the first Bezier must be horizontal, and the second
+ * must be vertical (except as noted below).
+ * If there is a multiple of four arguments, the curve starts
+ * horizontal and ends vertical. Note that the curves alternate
+ * between start horizontal, end vertical, and start vertical, and
+ * end horizontal. The last curve (the odd argument case) need not
+ * end horizontal/vertical.
+ */
+ private void _hvcurveto() {
+ if (getArgCount() % 8 <= 1) {
+ int count = getArgCount() / 8;
+ int[] dxa = new int[count];
+ int[] dxb = new int[count];
+ int[] dyb = new int[count];
+ int[] dyc = new int[count];
+ int[] dyd = new int[count];
+ int[] dxe = new int[count];
+ int[] dye = new int[count];
+ int[] dxf = new int[count];
+ int dyf = 0;
+ if (getArgCount() % 8 == 1) {
+ dyf = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ dxf[count - i - 1] = popArg().intValue();
+ dye[count - i - 1] = popArg().intValue();
+ dxe[count - i - 1] = popArg().intValue();
+ dyd[count - i - 1] = popArg().intValue();
+ dyc[count - i - 1] = popArg().intValue();
+ dyb[count - i - 1] = popArg().intValue();
+ dxb[count - i - 1] = popArg().intValue();
+ dxa[count - i - 1] = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ int xa = lastPoint.x + dxa[i];
+ int ya = lastPoint.y;
+ int xb = xa + dxb[i];
+ int yb = ya + dyb[i];
+ int xc = xb;
+ int yc = yb + dyc[i];
+ int xd = xc;
+ int yd = yc + dyd[i];
+ int xe = xd + dxe[i];
+ int ye = yd + dye[i];
+ int xf = xe + dxf[i];
+ int yf = ye + dyf;
+ curveTo(xa, ya, xb, yb, xc, yc);
+ curveTo(xd, yd, xe, ye, xf, yf);
+ }
+ } else {
+ int count = getArgCount() / 8;
+ int[] dya = new int[count];
+ int[] dxb = new int[count];
+ int[] dyb = new int[count];
+ int[] dxc = new int[count];
+ int[] dxd = new int[count];
+ int[] dxe = new int[count];
+ int[] dye = new int[count];
+ int[] dyf = new int[count];
+ int dxf = 0;
+ if (getArgCount() % 8 == 1) {
+ dxf = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ dyf[count - i - 1] = popArg().intValue();
+ dye[count - i - 1] = popArg().intValue();
+ dxe[count - i - 1] = popArg().intValue();
+ dxd[count - i - 1] = popArg().intValue();
+ dxc[count - i - 1] = popArg().intValue();
+ dyb[count - i - 1] = popArg().intValue();
+ dxb[count - i - 1] = popArg().intValue();
+ dya[count - i - 1] = popArg().intValue();
+ }
+ int dy3 = popArg().intValue();
+ int dy2 = popArg().intValue();
+ int dx2 = popArg().intValue();
+ int dx1 = popArg().intValue();
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ int xa = lastPoint.x;
+ int ya = lastPoint.y + dya[i];
+ int xb = xa + dxb[i];
+ int yb = ya + dyb[i];
+ int xc = xb + dxc[i];
+ int yc = yb;
+ int xd = xc + dxd[i];
+ int yd = yc;
+ int xe = xd + dxe[i];
+ int ye = yd + dye[i];
+ int xf = xe + dxf;
+ int yf = ye + dyf[i];
+ curveTo(xa, ya, xb, yb, xc, yc);
+ curveTo(xd, yd, xe, ye, xf, yf);
+
+ // What on earth do we do with dx1, dx2, dy2 and dy3?
+ }
+ }
+ clearArg();
+ }
+
+ /**
+ * Is equivalent to one rrcurveto for each set of six arguments
+ * dxa...dyc, followed by exactly one rlineto using the dxd, dyd
+ * arguments. The number of curves is determined from the count
+ * on the argument stack.
+ */
+ private void _rcurveline() {
+ int count = (getArgCount() - 2) / 6;
+ int[] dxa = new int[count];
+ int[] dya = new int[count];
+ int[] dxb = new int[count];
+ int[] dyb = new int[count];
+ int[] dxc = new int[count];
+ int[] dyc = new int[count];
+ int dyd = popArg().intValue();
+ int dxd = popArg().intValue();
+ for (int i = 0; i < count; ++i) {
+ dyc[count - i - 1] = popArg().intValue();
+ dxc[count - i - 1] = popArg().intValue();
+ dyb[count - i - 1] = popArg().intValue();
+ dxb[count - i - 1] = popArg().intValue();
+ dya[count - i - 1] = popArg().intValue();
+ dxa[count - i - 1] = popArg().intValue();
+ }
+ int xc = 0;
+ int yc = 0;
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ int xa = lastPoint.x + dxa[i];
+ int ya = lastPoint.y + dya[i];
+ int xb = xa + dxb[i];
+ int yb = ya + dyb[i];
+ xc = xb + dxc[i];
+ yc = yb + dyc[i];
+ curveTo(xa, ya, xb, yb, xc, yc);
+ }
+ lineTo(xc + dxd, yc + dyd);
+ clearArg();
+ }
+
+ /**
+ * Is equivalent to one rlineto for each pair of arguments beyond
+ * the six arguments dxb...dyd needed for the one rrcurveto
+ * command. The number of lines is determined from the count of
+ * items on the argument stack.
+ */
+ private void _rlinecurve() {
+ int count = (getArgCount() - 6) / 2;
+ int[] dxa = new int[count];
+ int[] dya = new int[count];
+ int dyd = popArg().intValue();
+ int dxd = popArg().intValue();
+ int dyc = popArg().intValue();
+ int dxc = popArg().intValue();
+ int dyb = popArg().intValue();
+ int dxb = popArg().intValue();
+ for (int i = 0; i < count; ++i) {
+ dya[count - i - 1] = popArg().intValue();
+ dxa[count - i - 1] = popArg().intValue();
+ }
+ int xa = 0;
+ int ya = 0;
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ xa = lastPoint.x + dxa[i];
+ ya = lastPoint.y + dya[i];
+ lineTo(xa, ya);
+ }
+ int xb = xa + dxb;
+ int yb = ya + dyb;
+ int xc = xb + dxc;
+ int yc = yb + dyc;
+ int xd = xc + dxd;
+ int yd = yc + dyd;
+ curveTo(xb, yb, xc, yc, xd, yd);
+ clearArg();
+ }
+
+ /**
+ * Appends one or more Bezier curves to the current point, where
+ * the first tangent is vertical and the second tangent is horizontal.
+ * This command is the complement of hvcurveto; see the
+ * description of hvcurveto for more information.
+ */
+ private void _vhcurveto() {
+ if (getArgCount() % 8 <= 1) {
+ int count = getArgCount() / 8;
+ int[] dya = new int[count];
+ int[] dxb = new int[count];
+ int[] dyb = new int[count];
+ int[] dxc = new int[count];
+ int[] dxd = new int[count];
+ int[] dxe = new int[count];
+ int[] dye = new int[count];
+ int[] dyf = new int[count];
+ int dxf = 0;
+ if (getArgCount() % 8 == 1) {
+ dxf = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ dyf[count - i - 1] = popArg().intValue();
+ dye[count - i - 1] = popArg().intValue();
+ dxe[count - i - 1] = popArg().intValue();
+ dxd[count - i - 1] = popArg().intValue();
+ dxc[count - i - 1] = popArg().intValue();
+ dyb[count - i - 1] = popArg().intValue();
+ dxb[count - i - 1] = popArg().intValue();
+ dya[count - i - 1] = popArg().intValue();
+ }
+ for (int i = 0; i < count; ++i) {
+ Point lastPoint = getLastPoint();
+ int xa = lastPoint.x;
+ int ya = lastPoint.y + dya[i];
+ int xb = xa + dxb[i];
+ int yb = ya + dyb[i];
+ int xc = xb + dxc[i];
+ int yc = yb;
+ int xd = xc + dxd[i];
+ int yd = yc;
+ int xe = xd + dxe[i];
+ int ye = yd + dye[i];
+ int xf = xe + dxf;
+ int yf = ye + dyf[i];
+ curveTo(xa, ya, xb, yb, xc, yc);
+ curveTo(xd, yd, xe, ye, xf, yf);
+ }
+ } else {
+ int foo = 0;
+ }
+ clearArg();
+ }
+
+ /**
+ * Appends one or more curves to the current point. If the argument
+ * count is a multiple of four, the curve starts and ends vertical. If
+ * the argument count is odd, the first curve does not begin with a
+ * vertical tangent.
+ */
+ private void _vvcurveto() {
+
+ clearArg();
+ }
+
+ /**
+ * Causes two B�zier curves, as described by the arguments (as
+ * shown in Figure 2 below), to be rendered as a straight line when
+ * the flex depth is less than fd /100 device pixels, and as curved lines
+ * when the flex depth is greater than or equal to fd/100 device
+ * pixels.
+ */
+ private void _flex() {
+
+ clearArg();
+ }
+
+ /**
+ * Causes the two curves described by the arguments dx1...dx6 to
+ * be rendered as a straight line when the flex depth is less than
+ * 0.5 (that is, fd is 50) device pixels, and as curved lines when the
+ * flex depth is greater than or equal to 0.5 device pixels.
+ */
+ private void _hflex() {
+
+ clearArg();
+ }
+
+ /**
+ * Causes the two curves described by the arguments to be
+ * rendered as a straight line when the flex depth is less than 0.5
+ * device pixels, and as curved lines when the flex depth is greater
+ * than or equal to 0.5 device pixels.
+ */
+ private void _hflex1() {
+
+ clearArg();
+ }
+
+ /**
+ * Causes the two curves described by the arguments to be
+ * rendered as a straight line when the flex depth is less than 0.5
+ * device pixels, and as curved lines when the flex depth is greater
+ * than or equal to 0.5 device pixels.
+ */
+ private void _flex1() {
+
+ clearArg();
+ }
+
+ /**
+ * Finishes a charstring outline definition, and must be the
+ * last operator in a character�s outline.
+ */
+ private void _endchar() {
+ endContour();
+ clearArg();
+ }
+
+ private void _hstem() {
+
+ clearArg();
+ }
+
+ private void _vstem() {
+
+ clearArg();
+ }
+
+ private void _hstemhm() {
+
+ clearArg();
+ }
+
+ private void _vstemhm() {
+
+ clearArg();
+ }
+
+ private void _hintmask() {
+
+ clearArg();
+ }
+
+ private void _cntrmask() {
+
+ clearArg();
+ }
+
+ /**
+ * Returns the absolute value of num.
+ */
+ private void _abs() {
+ double num = popArg().doubleValue();
+ pushArg(Math.abs(num));
+ }
+
+ /**
+ * Returns the sum of the two numbers num1 and num2.
+ */
+ private void _add() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg(num1 + num2);
+ }
+
+ /**
+ * Returns the result of subtracting num2 from num1.
+ */
+ private void _sub() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg(num1 - num2);
+ }
+
+ /**
+ * Returns the quotient of num1 divided by num2. The result is
+ * undefined if overflow occurs and is zero for underflow.
+ */
+ private void _div() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg(num1 / num2);
+ }
+
+ /**
+ * Returns the negative of num.
+ */
+ private void _neg() {
+ double num = popArg().doubleValue();
+ pushArg(-num);
+ }
+
+ /**
+ * Returns a pseudo random number num2 in the range (0,1], that
+ * is, greater than zero and less than or equal to one.
+ */
+ private void _random() {
+ pushArg(1.0 - Math.random());
+ }
+
+ /**
+ * Returns the product of num1 and num2. If overflow occurs, the
+ * result is undefined, and zero is returned for underflow.
+ */
+ private void _mul() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg(num1 * num2);
+ }
+
+ /**
+ * Returns the square root of num. If num is negative, the result is
+ * undefined.
+ */
+ private void _sqrt() {
+ double num = popArg().doubleValue();
+ pushArg(Math.sqrt(num));
+ }
+
+ /**
+ * Removes the top element num from the Type 2 argument stack.
+ */
+ private void _drop() {
+ popArg();
+ }
+
+ /**
+ * Exchanges the top two elements on the argument stack.
+ */
+ private void _exch() {
+ Number num2 = popArg();
+ Number num1 = popArg();
+ pushArg(num2);
+ pushArg(num1);
+ }
+
+ /**
+ * Retrieves the element i from the top of the argument stack and
+ * pushes a copy of that element onto that stack. If i is negative,
+ * the top element is copied. If i is greater than X, the operation is
+ * undefined.
+ */
+ private void _index() {
+ int i = popArg().intValue();
+ Number[] nums = new Number[i];
+ for (int j = 0; j < i; ++j) {
+ nums[j] = popArg();
+ }
+ for (int j = i - 1; j >= 0; --j) {
+ pushArg(nums[j]);
+ }
+ pushArg(nums[i]);
+ }
+
+ /**
+ * Performs a circular shift of the elements num(N�1) ... num0 on
+ * the argument stack by the amount J. Positive J indicates upward
+ * motion of the stack; negative J indicates downward motion.
+ * The value N must be a non-negative integer, otherwise the
+ * operation is undefined.
+ */
+ private void _roll() {
+ int j = popArg().intValue();
+ int n = popArg().intValue();
+ Number[] nums = new Number[n];
+ for (int i = 0; i < n; ++i) {
+ nums[i] = popArg();
+ }
+ for (int i = n - 1; i >= 0; --i) {
+ pushArg(nums[(n + i + j) % n]);
+ }
+ }
+
+ /**
+ * Duplicates the top element on the argument stack.
+ */
+ private void _dup() {
+ Number any = popArg();
+ pushArg(any);
+ pushArg(any);
+ }
+
+ /**
+ * Stores val into the transient array at the location given by i.
+ */
+ private void _put() {
+ int i = popArg().intValue();
+ Number val = popArg();
+ _transientArray[i] = val;
+ }
+
+ /**
+ * Retrieves the value stored in the transient array at the location
+ * given by i and pushes the value onto the argument stack. If get
+ * is executed prior to put for i during execution of the current
+ * charstring, the value returned is undefined.
+ */
+ private void _get() {
+ int i = popArg().intValue();
+ pushArg(_transientArray[i]);
+ }
+
+ /**
+ * Puts a 1 on the stack if num1 and num2 are both non-zero, and
+ * puts a 0 on the stack if either argument is zero.
+ */
+ private void _and() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg((num1!=0.0) && (num2!=0.0) ? 1 : 0);
+ }
+
+ /**
+ * Puts a 1 on the stack if either num1 or num2 are non-zero, and
+ * puts a 0 on the stack if both arguments are zero.
+ */
+ private void _or() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg((num1!=0.0) || (num2!=0.0) ? 1 : 0);
+ }
+
+ /**
+ * Returns a 0 if num1 is non-zero; returns a 1 if num1 is zero.
+ */
+ private void _not() {
+ double num1 = popArg().doubleValue();
+ pushArg((num1!=0.0) ? 0 : 1);
+ }
+
+ /**
+ * Puts a 1 on the stack if num1 equals num2, otherwise a 0 (zero)
+ * is put on the stack.
+ */
+ private void _eq() {
+ double num2 = popArg().doubleValue();
+ double num1 = popArg().doubleValue();
+ pushArg(num1 == num2 ? 1 : 0);
+ }
+
+ /**
+ * Leaves the value s1 on the stack if v1 ? v2, or leaves s2 on the
+ * stack if v1 > v2. The value of s1 and s2 is usually the biased
+ * number of a subroutine.
+ */
+ private void _ifelse() {
+ double v2 = popArg().doubleValue();
+ double v1 = popArg().doubleValue();
+ Number s2 = popArg();
+ Number s1 = popArg();
+ pushArg(v1 <= v2 ? s1 : s2);
+ }
+
+ /**
+ * Calls a charstring subroutine with index subr# (actually the subr
+ * number plus the subroutine bias number, as described in section
+ * 2.3) in the Subrs array. Each element of the Subrs array is a
+ * charstring encoded like any other charstring. Arguments
+ * pushed on the Type 2 argument stack prior to calling the
+ * subroutine, and results pushed on this stack by the subroutine,
+ * act according to the manner in which the subroutine is coded.
+ * Calling an undefined subr (gsubr) has undefined results.
+ */
+ private void _callsubr() {
+
+ }
+
+ /**
+ * Operates in the same manner as callsubr except that it calls a
+ * global subroutine.
+ */
+ private void _callgsubr() {
+
+ }
+
+ /**
+ * Returns from either a local or global charstring subroutine, and
+ * continues execution after the corresponding call(g)subr.
+ */
+ private void _return() {
+
+ }
+
+ public Point[] execute(CharstringType2 cs) {
+ _points = new ArrayList<Point>();
+ cs.resetIP();
+ while (cs.moreBytes()) {
+ while (cs.isOperandAtIndex()) {
+ pushArg(cs.nextOperand());
+ }
+ int operator = cs.nextByte();
+ if (operator == 12) {
+ operator = cs.nextByte();
+
+ // Two-byte operators
+ switch (operator) {
+ case T2Mnemonic.AND:
+ _and();
+ break;
+ case T2Mnemonic.OR:
+ _or();
+ break;
+ case T2Mnemonic.NOT:
+ _not();
+ break;
+ case T2Mnemonic.ABS:
+ _abs();
+ break;
+ case T2Mnemonic.ADD:
+ _add();
+ break;
+ case T2Mnemonic.SUB:
+ _sub();
+ break;
+ case T2Mnemonic.DIV:
+ _div();
+ break;
+ case T2Mnemonic.NEG:
+ _neg();
+ break;
+ case T2Mnemonic.EQ:
+ _eq();
+ break;
+ case T2Mnemonic.DROP:
+ _drop();
+ break;
+ case T2Mnemonic.PUT:
+ _put();
+ break;
+ case T2Mnemonic.GET:
+ _get();
+ break;
+ case T2Mnemonic.IFELSE:
+ _ifelse();
+ break;
+ case T2Mnemonic.RANDOM:
+ _random();
+ break;
+ case T2Mnemonic.MUL:
+ _mul();
+ break;
+ case T2Mnemonic.SQRT:
+ _sqrt();
+ break;
+ case T2Mnemonic.DUP:
+ _dup();
+ break;
+ case T2Mnemonic.EXCH:
+ _exch();
+ break;
+ case T2Mnemonic.INDEX:
+ _index();
+ break;
+ case T2Mnemonic.ROLL:
+ _roll();
+ break;
+ case T2Mnemonic.HFLEX:
+ _hflex();
+ break;
+ case T2Mnemonic.FLEX:
+ _flex();
+ break;
+ case T2Mnemonic.HFLEX1:
+ _hflex1();
+ break;
+ case T2Mnemonic.FLEX1:
+ _flex1();
+ break;
+ default:
+ //throw new Exception();
+ return null;
+ }
+ } else {
+
+ // One-byte operators
+ switch (operator) {
+ case T2Mnemonic.HSTEM:
+ _hstem();
+ break;
+ case T2Mnemonic.VSTEM:
+ _vstem();
+ break;
+ case T2Mnemonic.VMOVETO:
+ _vmoveto();
+ break;
+ case T2Mnemonic.RLINETO:
+ _rlineto();
+ break;
+ case T2Mnemonic.HLINETO:
+ _hlineto();
+ break;
+ case T2Mnemonic.VLINETO:
+ _vlineto();
+ break;
+ case T2Mnemonic.RRCURVETO:
+ _rrcurveto();
+ break;
+ case T2Mnemonic.CALLSUBR:
+ _callsubr();
+ break;
+ case T2Mnemonic.RETURN:
+ _return();
+ break;
+ case T2Mnemonic.ENDCHAR:
+ _endchar();
+ break;
+ case T2Mnemonic.HSTEMHM:
+ _hstemhm();
+ break;
+ case T2Mnemonic.HINTMASK:
+ _hintmask();
+ break;
+ case T2Mnemonic.CNTRMASK:
+ _cntrmask();
+ break;
+ case T2Mnemonic.RMOVETO:
+ _rmoveto();
+ break;
+ case T2Mnemonic.HMOVETO:
+ _hmoveto();
+ break;
+ case T2Mnemonic.VSTEMHM:
+ _vstemhm();
+ break;
+ case T2Mnemonic.RCURVELINE:
+ _rcurveline();
+ break;
+ case T2Mnemonic.RLINECURVE:
+ _rlinecurve();
+ break;
+ case T2Mnemonic.VVCURVETO:
+ _vvcurveto();
+ break;
+ case T2Mnemonic.HHCURVETO:
+ _hhcurveto();
+ break;
+ case T2Mnemonic.CALLGSUBR:
+ _callgsubr();
+ break;
+ case T2Mnemonic.VHCURVETO:
+ _vhcurveto();
+ break;
+ case T2Mnemonic.HVCURVETO:
+ _hvcurveto();
+ break;
+ default:
+ //throw new Exception();
+ return null;
+ }
+ }
+ }
+ Point[] pointArray = new Point[_points.size()];
+ _points.toArray(pointArray);
+ return pointArray;
+ }
+
+ /**
+ * The number of arguments on the argument stack
+ */
+ private int getArgCount() {
+ return _argStackIndex;
+ }
+
+ /**
+ * Pop a value off the argument stack
+ */
+ private Number popArg() {
+ return _argStack[--_argStackIndex];
+ }
+
+ /**
+ * Push a value on to the argument stack
+ */
+ private void pushArg(Number n) {
+ _argStack[_argStackIndex++] = n;
+ }
+
+ /**
+ * Pop a value off the subroutine stack
+ */
+ private int popSubr() {
+ return _subrStack[--_subrStackIndex];
+ }
+
+ /**
+ * Push a value on to the subroutine stack
+ */
+ private void pushSubr(int n) {
+ _subrStack[_subrStackIndex++] = n;
+ }
+
+ /**
+ * Clear the argument stack
+ */
+ private void clearArg() {
+ _argStackIndex = 0;
+ }
+
+ private Point getLastPoint() {
+ int size = _points.size();
+ if (size > 0) {
+ return _points.get(size - 1);
+ } else {
+ return new Point(0, 0, true, false);
+ }
+ }
+
+ private void moveTo(int x, int y) {
+ endContour();
+ _points.add(new Point(x, y, true, false));
+ }
+
+ private void lineTo(int x, int y) {
+ _points.add(new Point(x, y, true, false));
+ }
+
+ private void curveTo(int cx1, int cy1, int cx2, int cy2, int x, int y) {
+ _points.add(new Point(cx1, cy1, false, false));
+ _points.add(new Point(cx2, cy2, false, false));
+ _points.add(new Point(x, y, true, false));
+ }
+
+ private void endContour() {
+ Point lastPoint = getLastPoint();
+ if (lastPoint != null) {
+ lastPoint.endOfContour = true;
+ }
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/t2/T2Mnemonic.java b/src/typecast/net/java/dev/typecast/t2/T2Mnemonic.java
new file mode 100644
index 000000000..810aea159
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/t2/T2Mnemonic.java
@@ -0,0 +1,86 @@
+/*
+ * $Id: T2Mnemonic.java,v 1.1 2007-02-21 12:30:48 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004-2007 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.t2;
+
+/**
+ * The Mnemonic representations of the Type 2 charstring instruction set.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: T2Mnemonic.java,v 1.1 2007-02-21 12:30:48 davidsch Exp $
+ */
+public class T2Mnemonic {
+
+ /**
+ * One byte operators
+ */
+ public static final short HSTEM = 0x01;
+ public static final short VSTEM = 0x03;
+ public static final short VMOVETO = 0x04;
+ public static final short RLINETO = 0x05;
+ public static final short HLINETO = 0x06;
+ public static final short VLINETO = 0x07;
+ public static final short RRCURVETO = 0x08;
+ public static final short CALLSUBR = 0x0a;
+ public static final short RETURN = 0x0b;
+ public static final short ESCAPE = 0x0c;
+ public static final short ENDCHAR = 0x0e;
+ public static final short HSTEMHM = 0x12;
+ public static final short HINTMASK = 0x13;
+ public static final short CNTRMASK = 0x14;
+ public static final short RMOVETO = 0x15;
+ public static final short HMOVETO = 0x16;
+ public static final short VSTEMHM = 0x17;
+ public static final short RCURVELINE = 0x18;
+ public static final short RLINECURVE = 0x19;
+ public static final short VVCURVETO = 0x1a;
+ public static final short HHCURVETO = 0x1b;
+ public static final short CALLGSUBR = 0x1d;
+ public static final short VHCURVETO = 0x1e;
+ public static final short HVCURVETO = 0x1f;
+
+ /**
+ * Two byte operators
+ */
+ public static final short DOTSECTION = 0x00;
+ public static final short AND = 0x03;
+ public static final short OR = 0x04;
+ public static final short NOT = 0x05;
+ public static final short ABS = 0x09;
+ public static final short ADD = 0x0a;
+ public static final short SUB = 0x0b;
+ public static final short DIV = 0x0c;
+ public static final short NEG = 0x0e;
+ public static final short EQ = 0x0f;
+ public static final short DROP = 0x12;
+ public static final short PUT = 0x14;
+ public static final short GET = 0x15;
+ public static final short IFELSE = 0x16;
+ public static final short RANDOM = 0x17;
+ public static final short MUL = 0x18;
+ public static final short SQRT = 0x1a;
+ public static final short DUP = 0x1b;
+ public static final short EXCH = 0x1c;
+ public static final short INDEX = 0x1d;
+ public static final short ROLL = 0x1e;
+ public static final short HFLEX = 0x22;
+ public static final short FLEX = 0x23;
+ public static final short HFLEX1 = 0x24;
+ public static final short FLEX1 = 0x25;
+}
diff --git a/src/typecast/net/java/dev/typecast/tt/engine/GraphicsState.java b/src/typecast/net/java/dev/typecast/tt/engine/GraphicsState.java
new file mode 100644
index 000000000..1c36bd3de
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/tt/engine/GraphicsState.java
@@ -0,0 +1,50 @@
+/*
+ * $Id: GraphicsState.java,v 1.1.1.1 2004-12-05 23:15:01 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.tt.engine;
+
+/**
+ * Maintains the graphics state whilst interpreting hinting instructions.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: GraphicsState.java,v 1.1.1.1 2004-12-05 23:15:01 davidsch Exp $
+ */
+class GraphicsState {
+
+ public boolean auto_flip = true;
+ public int control_value_cut_in = 0;
+ public int delta_base = 9;
+ public int delta_shift = 3;
+ public int dual_projection_vectors;
+ public int[] freedom_vector = new int[2];
+ public int zp0 = 1;
+ public int zp1 = 1;
+ public int zp2 = 1;
+ public int instruction_control = 0;
+ public int loop = 1;
+ public int minimum_distance = 1;
+ public int[] projection_vector = new int[2];
+ public int round_state = 1;
+ public int rp0 = 0;
+ public int rp1 = 0;
+ public int rp2 = 0;
+ public int scan_control = 0;
+ public int single_width_cut_in = 0;
+ public int single_width_value = 0;
+}
diff --git a/src/typecast/net/java/dev/typecast/tt/engine/Interpreter.java b/src/typecast/net/java/dev/typecast/tt/engine/Interpreter.java
new file mode 100644
index 000000000..6f436d764
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/tt/engine/Interpreter.java
@@ -0,0 +1,1357 @@
+/*
+ * $Id: Interpreter.java,v 1.1.1.1 2004-12-05 23:15:05 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.tt.engine;
+
+import net.java.dev.typecast.ot.Mnemonic;
+import net.java.dev.typecast.ot.Point;
+
+/**
+ * The interpreter shall remain ignorant of the table structure - the table
+ * data will be extracted by supporting classes, whether it be the Parser
+ * or some other.
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Interpreter.java,v 1.1.1.1 2004-12-05 23:15:05 davidsch Exp $
+ */
+public class Interpreter {
+
+ private Parser parser = null;
+ private GraphicsState gs = new GraphicsState();
+ private Point[][] zone = new Point[2][];
+ private int[] stack = null;
+ private int[] store = null;
+ private int[] cvt = new int[256];
+ private int[] functionMap = null;
+ private int stackIndex = 0;
+ private boolean inFuncDef = false;
+
+ public Interpreter(int stackMax, int storeMax, int funcMax) {
+ zone[0] = new Point[256];
+ zone[1] = new Point[256];
+ stack = new int[stackMax];
+ store = new int[storeMax];
+ functionMap = new int[funcMax];
+ }
+
+ /**
+ * ABSolute value
+ */
+ private void _abs() {
+ int n = pop();
+ if (n >= 0) {
+ push(n);
+ } else {
+ push(-n);
+ }
+ }
+
+ /**
+ * ADD
+ */
+ private void _add() {
+ int n1 = pop();
+ int n2 = pop();
+ push(n2 + n1);
+ }
+
+ private void _alignpts() {
+ pop();
+ pop();
+ }
+
+ /**
+ *
+ *
+ * USES: loop
+ */
+ private void _alignrp() {
+ while (gs.loop-- > 0) {
+ pop();
+ }
+ gs.loop = 1;
+ }
+
+ /**
+ * logical AND
+ */
+ private void _and() {
+ int e2 = pop();
+ int e1 = pop();
+ push(((e1 != 0) && (e2 != 0)) ? 1 : 0);
+ }
+
+ /**
+ * CALL function
+ */
+ private void _call() {
+ execute(functionMap[pop()]);
+ }
+
+ /**
+ * CEILING
+ */
+ private void _ceiling() {
+ int n = pop();
+ if (n >= 0) {
+ push((n & 0xffc0) + (((n & 0x3f) != 0) ? 0x40 : 0));
+ } else {
+ push(n & 0xffc0);
+ }
+ }
+
+ /**
+ * Copy the INDEXed element to the top of the stack
+ */
+ private void _cindex() {
+ push(stack[stackIndex - pop()]);
+ }
+
+ /**
+ * CLEAR the entire stack
+ */
+ private void _clear() {
+ stackIndex = 0;
+ }
+
+ private void _debug() {
+ pop();
+ }
+
+ /**
+ * DELTA exception C1
+ */
+ private void _deltac1() {
+ int n = pop();
+ for (int i = 0; i < n; i++) {
+ pop(); // pn
+ pop(); // argn
+ }
+ }
+
+ /**
+ * DELTA exception C2
+ */
+ private void _deltac2() {
+ int n = pop();
+ for (int i = 0; i < n; i++) {
+ pop(); // pn
+ pop(); // argn
+ }
+ }
+
+ /**
+ * DELTA exception C3
+ */
+ private void _deltac3() {
+ int n = pop();
+ for (int i = 0; i < n; i++) {
+ pop(); // pn
+ pop(); // argn
+ }
+ }
+
+ /**
+ * DELTA exception P1
+ */
+ private void _deltap1() {
+ int n = pop();
+ for (int i = 0; i < n; i++) {
+ pop(); // pn
+ pop(); // argn
+ }
+ }
+
+ /**
+ * DELTA exception P2
+ */
+ private void _deltap2() {
+ int n = pop();
+ for (int i = 0; i < n; i++) {
+ pop(); // pn
+ pop(); // argn
+ }
+ }
+
+ /**
+ * DELTA exception P3
+ */
+ private void _deltap3() {
+ int n = pop();
+ for (int i = 0; i < n; i++) {
+ pop(); // pn
+ pop(); // argn
+ }
+ }
+
+ /**
+ * Returns the DEPTH of the stack
+ */
+ private void _depth() {
+ push(stackIndex);
+ }
+
+ /**
+ * DIVide
+ */
+ private void _div() {
+ int n1 = pop();
+ int n2 = pop();
+ push((n2 / n1) >> 6);
+ }
+
+ /**
+ * DUPlicate top stack element
+ */
+ private void _dup() {
+ int n = pop();
+ push(n);
+ push(n);
+ }
+
+ /**
+ * ELSE
+ */
+ private int _else(int instructionIndex) {
+ return parser.handleElse(instructionIndex);
+ }
+
+ /**
+ * EQual
+ */
+ private void _eq() {
+ int e2 = pop();
+ int e1 = pop();
+ push((e1 == e2) ? 1 : 0);
+ }
+
+ private void _even() {
+ pop();
+ push(0);
+ }
+
+ /**
+ * Function DEFinition
+ */
+ private void _fdef(int instructionIndex) {
+ functionMap[pop()] = instructionIndex;
+ inFuncDef = true;
+ }
+
+ /**
+ * Set the auto_FLIP boolean to OFF
+ */
+ private void _flipoff() {
+ gs.auto_flip = false;
+ }
+
+ /**
+ * Set the auto_FLIP boolean to ON
+ */
+ private void _flipon() {
+ gs.auto_flip = true;
+ }
+
+ /**
+ * FLIP PoinT
+ *
+ * USES: loop
+ */
+ private void _flippt() {
+ while(gs.loop-- > 0) {
+ int index = pop();
+ zone[gs.zp0][index].onCurve = !zone[gs.zp0][index].onCurve;
+ }
+ gs.loop = 1;
+ }
+
+ /**
+ * FLIP RanGe OFF
+ */
+ private void _fliprgoff() {
+ int end = pop();
+ int start = pop();
+ for (int i = start; i <= end; i++) {
+ zone[1][i].onCurve = false;
+ }
+ }
+
+ /**
+ * FLIP RanGe ON
+ */
+ private void _fliprgon() {
+ int end = pop();
+ int start = pop();
+ for (int i = start; i <= end; i++) {
+ zone[1][i].onCurve = true;
+ }
+ }
+
+ /**
+ * FLOOR
+ */
+ private void _floor() {
+ int n = pop();
+ if (n >= 0) {
+ push(n & 0xffc0);
+ } else {
+ push((n & 0xffc0) - (((n & 0x3f) != 0) ? 0x40 : 0));
+ }
+ }
+
+ private void _gc(short param) {
+ pop();
+ push(0);
+ }
+
+ private void _getinfo() {
+ pop();
+ push(0);
+ }
+
+ /**
+ * Get Freedom_Vector
+ */
+ private void _gfv() {
+ push(gs.freedom_vector[0]);
+ push(gs.freedom_vector[1]);
+ }
+
+ /**
+ * Get Projection_Vector
+ */
+ private void _gpv() {
+ push(gs.projection_vector[0]);
+ push(gs.projection_vector[1]);
+ }
+
+ /**
+ * Greater Than
+ */
+ private void _gt() {
+ int e2 = pop();
+ int e1 = pop();
+ push((e1 > e2) ? 1 : 0);
+ }
+
+ /**
+ * Greater Than or EQual
+ */
+ private void _gteq() {
+ int e2 = pop();
+ int e1 = pop();
+ push((e1 >= e2) ? 1 : 0);
+ }
+
+ /**
+ * Instruction DEFinition
+ */
+ private void _idef() {
+ pop();
+ inFuncDef = true;
+ }
+
+ /**
+ * IF test
+ */
+ private int _if(int instructionIndex) {
+ return parser.handleIf(pop() != 0, instructionIndex);
+ }
+
+ /**
+ * INSTruction Execution ConTRol
+ *
+ * INSTCTRL[]
+ *
+ * Code Range
+ * 0x8E
+ *
+ * Pops
+ * s: selector flag (int32)
+ * value: USHORT (padded to 32 bits) used to set value of instruction_control.
+ *
+ * Pushes
+ * -
+ *
+ * Sets
+ * instruction_control
+ *
+ * Sets the instruction control state variable making it possible to turn on or off
+ * the execution of instructions and to regulate use of parameters set in the CVT
+ * program. INSTCTRL[ ] can only be executed in the CVT program.
+ *
+ * This instruction clears and sets various control flags in the rasterizer. The
+ * selector flag determines valid values for the value argument. The value determines
+ * the new setting of the raterizer control flag. In version 1.0 there are only two
+ * flags in use:
+ *
+ * Selector flag 1 is used to inhibit grid-fitting. If s=1, valid values for the
+ * value argument are 0 (FALSE) and 1 (TRUE). If the value argument is set to TRUE
+ * (v=1), any instructions associated with glyphs will not be executed. For example,
+ * to inhibit grid-fitting when a glyph is being rotated or stretched, use the
+ * following sequence on the preprogram:
+ *
+ * PUSHB[000] 6 ; ask GETINFO to check for stretching or rotation
+ * GETINFO[] ; will push TRUE if glyph is stretched or rotated
+ * IF[] ; tests value at top of stack
+ * PUSHB[000] 1 ; value for INSTCTRL
+ * PUSHB[000] 1 ; selector for INSTCTRL
+ * INSTRCTRL[] ; based on selector and value will turn grid-fitting off
+ * EIF[]
+ *
+ * Selector flag 2 is used to establish that any parameters set in the CVT program
+ * should be ignored when instructions associated with glyphs are executed. These
+ * include, for example, the values for scantype and the CVT cut-in. If s=1, valid
+ * values for the value argument are 0 (FALSE) and 2 (TRUE). If the value argument is
+ * set to TRUE (v=2), the default values of those parameters will be used regardless
+ * of any changes that may have been made in those values by the preprogram. If the
+ * value argument is set to FALSE (v=0), parameter values changed by the CVT program
+ * will be used in glyph instructions.
+ */
+ private void _instctrl() {
+ int s = pop();
+ int v = pop();
+ if (s == 1) {
+ gs.instruction_control |= v;
+ } else if (s == 2) {
+ gs.instruction_control |= v;
+ }
+ }
+
+ private void _ip() {
+ pop();
+ }
+
+ private void _isect() {
+ pop();
+ pop();
+ pop();
+ pop();
+ pop();
+ }
+
+ private void _iup(short param) {
+ }
+
+ /**
+ * JuMP Relative
+ */
+ private int _jmpr(int instructionIndex) {
+ return instructionIndex += pop() - 1;
+ }
+
+ /**
+ * Jump Relative On False
+ */
+ private int _jrof(int instructionIndex) {
+ boolean test = pop() != 0;
+ int offset = pop();
+ if (!test) {
+ instructionIndex += offset - 1;
+ }
+ return instructionIndex;
+ }
+
+ /**
+ * Jump Relative On True
+ */
+ private int _jrot(int instructionIndex) {
+ boolean test = pop() != 0;
+ int offset = pop();
+ if (test) {
+ instructionIndex += offset - 1;
+ }
+ return instructionIndex;
+ }
+
+ /**
+ * LOOP and CALL function
+ */
+ private void _loopcall() {
+ int index = pop();
+ int count = pop();
+ for (int i = 0; i < count; i++) {
+ execute(functionMap[i]);
+ }
+ }
+
+ /**
+ * Less Than
+ */
+ private void _lt() {
+ int e2 = pop();
+ int e1 = pop();
+ push((e1 < e2) ? 1 : 0);
+ }
+
+ /**
+ * Less Than or EQual
+ */
+ private void _lteq() {
+ int e2 = pop();
+ int e1 = pop();
+ push((e1 <= e2) ? 1 : 0);
+ }
+
+ /**
+ * MAXimum of top two stack elements
+ */
+ private void _max() {
+ int n1 = pop();
+ int n2 = pop();
+ push((n1 > n2) ? n1 : n2);
+ }
+
+ private void _md(short param) {
+ pop();
+ pop();
+ push(0);
+ }
+
+ private void _mdap(short param) {
+ pop();
+ }
+
+ private void _mdrp(short param) {
+ pop();
+ }
+
+ private void _miap(short param) {
+ pop();
+ pop();
+ }
+ /**
+ * MINimum of top two stack elements
+ */
+ private void _min() {
+ int n1 = pop();
+ int n2 = pop();
+ push((n1 < n2) ? n1 : n2);
+ }
+
+ /**
+ * Move the INDEXed element to the top of the stack
+ */
+ private void _mindex() {
+ // Move the indexed element to stackIndex, and shift the others down
+ int k = pop();
+ int e = stack[stackIndex - k];
+ for (int i = stackIndex - k; i < stackIndex - 1; i++) {
+ stack[i] = stack[i+1];
+ }
+ stack[stackIndex - 1] = e;
+ }
+
+ private void _mirp(short param) {
+ pop();
+ pop();
+ }
+
+ private void _mppem() {
+ push(0);
+ }
+
+ private void _mps() {
+ push(0);
+ }
+
+ private void _msirp(short param) {
+ pop();
+ pop();
+ }
+
+ /**
+ * MULtiply
+ */
+ private void _mul() {
+ int n1 = pop();
+ int n2 = pop();
+ push((n1 * n2) >> 6);
+ }
+
+ /**
+ * NEGate
+ */
+ private void _neg() {
+ push(-pop());
+ }
+
+ /**
+ * Not EQual
+ */
+ private void _neq() {
+ int e2 = pop();
+ int e1 = pop();
+ push((e1 != e2) ? 1 : 0);
+ }
+
+ /**
+ * logical NOT
+ */
+ private void _not() {
+ push((pop() != 0) ? 0 : 1);
+ }
+
+ private void _nround(short param) {
+ pop();
+ push(0);
+ }
+
+ private void _odd() {
+ pop();
+ push(0);
+ }
+
+ /**
+ * logical OR
+ */
+ private void _or() {
+ int e2 = pop();
+ int e1 = pop();
+ push(((e1 != 0) || (e2 != 0)) ? 1 : 0);
+ }
+
+ /**
+ * PUSH N Bytes
+ * PUSH N Words
+ * PUSH Bytes
+ * PUSH Words
+ */
+ private void _push(int[] data) {
+ for (int j = 0; j < data.length; j++) {
+ push(data[j]);
+ }
+ }
+
+ /**
+ * Read Control Value Table
+ */
+ private void _rcvt() {
+ push(cvt[pop()]);
+ }
+
+ /**
+ * Round Down To Grid
+ */
+ private void _rdtg() {
+ gs.round_state = 3;
+ }
+
+ /**
+ * Round OFF
+ */
+ private void _roff() {
+ gs.round_state = 5;
+ }
+
+ /**
+ * ROLL the top three stack elements
+ */
+ private void _roll() {
+ int a = pop();
+ int b = pop();
+ int c = pop();
+ push(b);
+ push(a);
+ push(c);
+ }
+
+ private void _round(short param) {
+ pop();
+ push(0);
+ }
+
+ /**
+ * Read Store
+ */
+ private void _rs() {
+ push(store[pop()]);
+ }
+
+ /**
+ * Round To Double Grid
+ */
+ private void _rtdg() {
+ gs.round_state = 2;
+ }
+
+ /**
+ * Round To Grid
+ */
+ private void _rtg() {
+ gs.round_state = 1;
+ }
+
+ /**
+ * Round To Half Grid
+ */
+ private void _rthg() {
+ gs.round_state = 0;
+ }
+
+ /**
+ * Round Up To Grid
+ */
+ private void _rutg() {
+ gs.round_state = 4;
+ }
+
+ private void _s45round() {
+ pop();
+ }
+
+ /**
+ * SCAN conversion ConTRoL
+ *
+ * SCANCTRL[ ]
+ *
+ * Code Range
+ * 0x85
+ *
+ * Pops
+ * n: flags indicating when to turn on dropout control mode (16 bit word padded
+ * to 32 bits)
+ *
+ * Pushes
+ * -
+ *
+ * Sets
+ * scan_control
+ *
+ * SCANCTRL is used to set the value of the Graphics State variable scan_control
+ * which in turn determines whether the scan converter will activate dropout
+ * control for this glyph. Use of the dropout control mode is determined by three
+ * conditions:
+ *
+ * Is the glyph rotated?
+ *
+ * Is the glyph stretched?
+ *
+ * Is the current setting for ppem less than a specified threshold?
+ *
+ * The interpreter pops a word from the stack and looks at the lower 16 bits.
+ *
+ * Bits 0-7 represent the threshold value for ppem. A value of FF in bits 0-7
+ * means invoke dropout_control for all sizes. A value of 0 in bits 0-7 means
+ * never invoke dropout_control.
+ *
+ * Bits 8-13 are used to turn on dropout_control in cases where the specified
+ * conditions are met. Bits 8, 9 and 10 are used to turn on the dropout_control
+ * mode (assuming other conditions do not block it). Bits 11, 12, and 13 are
+ * used to turn off the dropout mode unless other conditions force it. Bits 14
+ * and 15 are reserved for future use.
+ *
+ * Bit Meaning if set
+ * --- --------------
+ * 8 Set dropout_control to TRUE if other conditions do not block and ppem
+ * is less than or equal to the threshold value.
+ *
+ * 9 Set dropout_control to TRUE if other conditions do not block and the
+ * glyph is rotated.
+ *
+ * 10 Set dropout_control to TRUE if other conditions do not block and the
+ * glyph is stretched.
+ *
+ * 11 Set dropout_control to FALSE unless ppem is less than or equal to the
+ * threshold value.
+ *
+ * 12 Set dropout_control to FALSE unless the glyph is rotated.
+ *
+ * 13 Set dropout_control to FALSE unless the glyph is stretched.
+ *
+ * 14 Reserved for future use.
+ *
+ * 15 Reserved for future use.
+ *
+ * For example
+ * 0x0000 No dropout control is invoked
+ * 0x01FF Always do dropout control
+ * 0x0A10 Do dropout control if the glyph is rotated and has less than 16
+ * pixels per-em
+ *
+ * The scan converter can operate in either a "normal" mode or in a "fix dropout"
+ * mode depending on the value of a set of enabling and disabling flags.
+ */
+ private void _scanctrl() {
+ gs.scan_control = pop();
+ }
+
+ /**
+ * SCANTYPE
+ *
+ * SCANTYPE[]
+ *
+ * Code Range
+ * 0x8D
+ *
+ * Pops
+ * n: 16 bit integer
+ *
+ * Pushes
+ * -
+ *
+ * Sets
+ * scan_control
+ *
+ * Pops a 16-bit integer whose value is used to determine which rules the scan
+ * converter will use. If the value of the argument is 0, the fast scan converter
+ * will be used. If the value of the integer is 1 or 2, simple dropout control will
+ * be used. If the value of the integer is 4 or 5, smart dropout control will be
+ * used. More specifically,
+ *
+ * if n=0 rules 1, 2, and 3 are invoked (simple dropout control scan conversion
+ * including stubs)
+ *
+ * if n=1 rules 1, 2, and 4 are invoked (simple dropout control scan conversion
+ * excluding stubs)
+ *
+ * if n=2 rules 1 and 2 only are invoked (fast scan conversion; dropout control
+ * turned off)
+ *
+ * if n=3 same as n = 2
+ *
+ * if n = 4 rules 1, 2, and 5 are invoked (smart dropout control scan conversion
+ * including stubs)
+ *
+ * if n = 5 rules 1, 2, and 6 are invoked (smart dropout control scan conversion
+ * excluding stubs)
+ *
+ * if n = 6 same as n = 2
+ *
+ * if n = 7 same as n = 2
+ *
+ * The scan conversion rules are shown here:
+ *
+ * Rule 1
+ * If a pixel's center falls within the glyph outline, that pixel is turned on.
+ *
+ * Rule 2
+ * If a contour falls exactly on a pixel's center, that pixel is turned on.
+ *
+ * Rule 3
+ * If a scan line between two adjacent pixel centers (either vertical or
+ * horizontal) is intersected by both an on-Transition contour and an off-Transition
+ * contour and neither of the pixels was already turned on by rules 1 and 2, turn on
+ * the left-most pixel (horizontal scan line) or the bottom-most pixel (vertical scan
+ * line). This is "Simple" dropout control.
+ *
+ * Rule 4
+ * Apply Rule 3 only if the two contours continue to intersect other scan lines in
+ * both directions. That is, do not turn on pixels for 'stubs.' The scanline segments
+ * that form a square with the intersected scan line segment are examined to verify
+ * that they are intersected by two contours. It is possible that these could be
+ * different contours than the ones intersecting the dropout scan line segment. This
+ * is very unlikely but may have to be controlled with grid-fitting in some exotic
+ * glyphs.
+ *
+ * Rule 5
+ * If a scan line between two adjacent pixel centers (either vertical or horizontal)
+ * is intersected by both an on-Transition contour and an off-Transition contour and
+ * neither of the pixels was already turned on by rules 1 and 2, turn on the pixel
+ * which is closer to the midpoint between the on-Transition contour and off-
+ * Transition contour. This is "Smart" dropout control.
+ *
+ * Rule 6
+ * Apply Rule 5 only if the two contours continue to intersect other scan lines in
+ * both directions. That is, do not turn on pixels for 'stubs.'
+ *
+ * New fonts wishing to use the new modes of the ScanType instruction, but still
+ * wishing to work correctly on old rasterizers that don't recognize the new modes
+ * should:
+ *
+ * First execute a ScanType instruction using an old mode which will give the best
+ * approximation to the desired new mode (e.g. Simple Stubs for Smart Stubs), and
+ * then
+ *
+ * Immediately execute another ScanType instruction with the desired new mode.
+ */
+ private void _scantype() {
+ pop();
+ }
+
+ private void _scfs() {
+ pop();
+ pop();
+ }
+
+ /**
+ * Set Control Value Table Cut In
+ */
+ private void _scvtci() {
+ gs.control_value_cut_in = pop();
+ }
+
+ /**
+ * Set Delta_Base in the graphics state
+ */
+ private void _sdb() {
+ gs.delta_base = pop();
+ }
+
+ /**
+ * Set Dual Projection_Vector To Line
+ */
+ private void _sdpvtl(short param) {
+ pop();
+ pop();
+ }
+
+ /**
+ * Set Delta_Shift in the graphics state
+ */
+ private void _sds() {
+ gs.delta_shift = pop();
+ }
+
+ /**
+ * Set Freedom_Vector From Stack
+ */
+ private void _sfvfs() {
+ gs.freedom_vector[1] = pop(); // y
+ gs.freedom_vector[0] = pop(); // x
+ }
+
+ /*
+ * Set Freedom_Vector to Coordinate Axis
+ */
+ private void _sfvtca(short param) {
+ if (param == 1) {
+ gs.freedom_vector[0] = 0x4000;
+ gs.freedom_vector[1] = 0x0000;
+ } else {
+ gs.freedom_vector[0] = 0x0000;
+ gs.freedom_vector[1] = 0x4000;
+ }
+ }
+
+ /*
+ * Set Freedom_Vector To Line
+ */
+ private void _sfvtl(short param) {
+ pop();
+ pop();
+ if (param == 1) {
+ gs.freedom_vector[0] = 0x0000;
+ gs.freedom_vector[1] = 0x0000;
+ } else {
+ gs.freedom_vector[0] = 0x0000;
+ gs.freedom_vector[1] = 0x0000;
+ }
+ }
+
+ /**
+ * Set Freedom_Vector To Projection Vector
+ */
+ private void _sfvtpv() {
+ gs.freedom_vector[0] = gs.projection_vector[0];
+ gs.freedom_vector[1] = gs.projection_vector[1];
+ }
+
+ private void _shc(short param) {
+ pop();
+ }
+
+ /**
+ * SHift Point by the last point
+ *
+ * USES: loop
+ */
+ private void _shp(short param) {
+ while(gs.loop-- > 0) {
+ pop();
+ if(param == 0) {
+ } else {
+ }
+ }
+ gs.loop = 1;
+ }
+
+ /**
+ * SHift Point by a PIXel amount
+ *
+ * USES: loop
+ */
+ private void _shpix() {
+ pop(); // amount
+ while (gs.loop-- > 0) {
+ pop(); // p
+ }
+ gs.loop = 1;
+ }
+
+ private void _shz(short param) {
+ pop();
+ }
+
+ /**
+ * Set LOOP variable
+ */
+ private void _sloop() {
+ gs.loop = pop();
+ }
+
+ /**
+ * Set Minimum_Distance
+ */
+ private void _smd() {
+ gs.minimum_distance = pop();
+ }
+
+ /**
+ * Set Projection_Vector From Stack
+ */
+ private void _spvfs() {
+ gs.projection_vector[1] = pop(); // y
+ gs.projection_vector[0] = pop(); // x
+ }
+
+ /*
+ * Set Projection_Vector To Coordinate Axis
+ */
+ private void _spvtca(short param) {
+ if (param == 1) {
+ gs.projection_vector[0] = 0x4000;
+ gs.projection_vector[1] = 0x0000;
+ } else {
+ gs.projection_vector[0] = 0x0000;
+ gs.projection_vector[1] = 0x4000;
+ }
+ }
+
+ /**
+ * Set Projection_Vector To Line
+ */
+ private void _spvtl(short param) {
+
+ // We'll get a copy of the line and normalize it -
+ // divide the x- and y-coords by the vector's dot product.
+ Point p1 = zone[gs.zp2][pop()];
+ Point p2 = zone[gs.zp1][pop()];
+ int x = p2.x - p1.x;
+ int y = p2.y - p1.y;
+ if(param == 1) {
+ gs.projection_vector[0] = 0x0000;
+ gs.projection_vector[1] = 0x0000;
+ } else {
+ gs.projection_vector[0] = 0x0000;
+ gs.projection_vector[1] = 0x0000;
+ }
+ }
+
+ private void _sround() {
+ pop();
+ }
+
+ /**
+ * Set Reference Point 0
+ */
+ private void _srp0() {
+ gs.rp0 = pop();
+ }
+
+ /**
+ * Set Reference Point 1
+ */
+ private void _srp1() {
+ gs.rp1 = pop();
+ }
+
+ /**
+ * Set Reference Point 2
+ */
+ private void _srp2() {
+ gs.rp2 = pop();
+ }
+
+ /**
+ * Set Single-Width
+ */
+ private void _ssw() {
+ gs.single_width_value = pop();
+ }
+
+ /**
+ * Set Single_Width_Cut_In
+ */
+ private void _sswci() {
+ gs.single_width_cut_in = pop();
+ }
+
+ /**
+ * SUBtract
+ */
+ private void _sub() {
+ int n1 = pop();
+ int n2 = pop();
+ push(n2 - n1);
+ }
+
+ /**
+ * Set freedom and projection Vectors To Coordinate Axis
+ */
+ private void _svtca(short param) {
+ if (param == 1) {
+ gs.projection_vector[0] = 0x4000;
+ gs.projection_vector[1] = 0x0000;
+ gs.freedom_vector[0] = 0x4000;
+ gs.freedom_vector[1] = 0x0000;
+ } else {
+ gs.projection_vector[0] = 0x0000;
+ gs.projection_vector[1] = 0x4000;
+ gs.freedom_vector[0] = 0x0000;
+ gs.freedom_vector[1] = 0x4000;
+ }
+ }
+
+ /**
+ * SWAP the top two elements on the stack
+ */
+ private void _swap() {
+ int n1 = pop();
+ int n2 = pop();
+ push(n1);
+ push(n2);
+ }
+
+ /**
+ * Set Zone Pointer 0
+ */
+ private void _szp0() {
+ gs.zp0 = pop();
+ }
+
+ /**
+ * Set Zone Pointer 1
+ */
+ private void _szp1() {
+ gs.zp1 = pop();
+ }
+
+ /**
+ * Set Zone Pointer 2
+ */
+ private void _szp2() {
+ gs.zp2 = pop();
+ }
+
+ /**
+ * Set Zone PointerS
+ */
+ private void _szps() {
+ gs.zp0 = gs.zp1 = gs.zp2 = pop();
+ }
+
+ private void _utp() {
+ pop();
+ }
+
+ /**
+ * Write Control Value Table in FUnits
+ */
+ private void _wcvtf() {
+ int value = pop();
+ // Conversion of value goes here
+ cvt[pop()] = value;
+ }
+
+ /**
+ * Write Control Value Table in Pixel units
+ */
+ private void _wcvtp() {
+ int value = pop();
+ // Conversion of value goes here
+ cvt[pop()] = value;
+ }
+
+ /**
+ * Write Store
+ */
+ private void _ws() {
+ store[pop()] = pop();
+ }
+
+ public void execute(int ip) {
+ while (ip < ((ip & 0xffff0000) | parser.getISLength(ip >> 16))) {
+ short opcode = parser.getOpcode(ip);
+ if (inFuncDef) {
+
+ // We're within a function definition, so don't execute the code
+ if (opcode == Mnemonic.ENDF) {
+ inFuncDef = false;
+ }
+ ip = parser.advanceIP(ip);
+ continue;
+ }
+ if (opcode >= Mnemonic.MIRP) _mirp((short)(opcode & 31));
+ else if (opcode >= Mnemonic.MDRP) _mdrp((short)(opcode & 31));
+ else if (opcode >= Mnemonic.PUSHW) _push(parser.getPushData(ip));
+ else if (opcode >= Mnemonic.PUSHB) _push(parser.getPushData(ip));
+ else if (opcode >= Mnemonic.INSTCTRL) _instctrl();
+ else if (opcode >= Mnemonic.SCANTYPE) _scantype();
+ else if (opcode >= Mnemonic.MIN) _min();
+ else if (opcode >= Mnemonic.MAX) _max();
+ else if (opcode >= Mnemonic.ROLL) _roll();
+ else if (opcode >= Mnemonic.IDEF) _idef();
+ else if (opcode >= Mnemonic.GETINFO) _getinfo();
+ else if (opcode >= Mnemonic.SDPVTL) _sdpvtl((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SCANCTRL) _scanctrl();
+ else if (opcode >= Mnemonic.FLIPRGOFF) _fliprgoff();
+ else if (opcode >= Mnemonic.FLIPRGON) _fliprgon();
+ else if (opcode >= Mnemonic.FLIPPT) _flippt();
+ else if (opcode >= Mnemonic.AA); // AA (ignored)
+ else if (opcode >= Mnemonic.SANGW); // SANGW (ignored)
+ else if (opcode >= Mnemonic.RDTG) _rdtg();
+ else if (opcode >= Mnemonic.RUTG) _rutg();
+ else if (opcode >= Mnemonic.ROFF) _roff();
+ else if (opcode >= Mnemonic.JROF) ip = _jrof(ip);
+ else if (opcode >= Mnemonic.JROT) ip = _jrot(ip);
+ else if (opcode >= Mnemonic.S45ROUND) _s45round();
+ else if (opcode >= Mnemonic.SROUND) _sround();
+ else if (opcode >= Mnemonic.DELTAC3) _deltac3();
+ else if (opcode >= Mnemonic.DELTAC2) _deltac2();
+ else if (opcode >= Mnemonic.DELTAC1) _deltac1();
+ else if (opcode >= Mnemonic.DELTAP3) _deltap3();
+ else if (opcode >= Mnemonic.DELTAP2) _deltap2();
+ else if (opcode >= Mnemonic.WCVTF) _wcvtf();
+ else if (opcode >= Mnemonic.NROUND) _nround((short)(opcode & 3));
+ else if (opcode >= Mnemonic.ROUND) _round((short)(opcode & 3));
+ else if (opcode >= Mnemonic.CEILING) _ceiling();
+ else if (opcode >= Mnemonic.FLOOR) _floor();
+ else if (opcode >= Mnemonic.NEG) _neg();
+ else if (opcode >= Mnemonic.ABS) _abs();
+ else if (opcode >= Mnemonic.MUL) _mul();
+ else if (opcode >= Mnemonic.DIV) _div();
+ else if (opcode >= Mnemonic.SUB) _sub();
+ else if (opcode >= Mnemonic.ADD) _add();
+ else if (opcode >= Mnemonic.SDS) _sds();
+ else if (opcode >= Mnemonic.SDB) _sdb();
+ else if (opcode >= Mnemonic.DELTAP1) _deltap1();
+ else if (opcode >= Mnemonic.NOT) _not();
+ else if (opcode >= Mnemonic.OR) _or();
+ else if (opcode >= Mnemonic.AND) _and();
+ else if (opcode >= Mnemonic.EIF); // EIF
+ else if (opcode >= Mnemonic.IF) ip = _if(ip);
+ else if (opcode >= Mnemonic.EVEN) _even();
+ else if (opcode >= Mnemonic.ODD) _odd();
+ else if (opcode >= Mnemonic.NEQ) _neq();
+ else if (opcode >= Mnemonic.EQ) _eq();
+ else if (opcode >= Mnemonic.GTEQ) _gteq();
+ else if (opcode >= Mnemonic.GT) _gt();
+ else if (opcode >= Mnemonic.LTEQ) _lteq();
+ else if (opcode >= Mnemonic.LT) _lt();
+ else if (opcode >= Mnemonic.DEBUG) _debug();
+ else if (opcode >= Mnemonic.FLIPOFF) _flipoff();
+ else if (opcode >= Mnemonic.FLIPON) _flipon();
+ else if (opcode >= Mnemonic.MPS) _mps();
+ else if (opcode >= Mnemonic.MPPEM) _mppem();
+ else if (opcode >= Mnemonic.MD) _md((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SCFS) _scfs();
+ else if (opcode >= Mnemonic.GC) _gc((short)(opcode & 1));
+ else if (opcode >= Mnemonic.RCVT) _rcvt();
+ else if (opcode >= Mnemonic.WCVTP) _wcvtp();
+ else if (opcode >= Mnemonic.RS) _rs();
+ else if (opcode >= Mnemonic.WS) _ws();
+ else if (opcode >= Mnemonic.NPUSHW) _push(parser.getPushData(ip));
+ else if (opcode >= Mnemonic.NPUSHB) _push(parser.getPushData(ip));
+ else if (opcode >= Mnemonic.MIAP) _miap((short)(opcode & 1));
+ else if (opcode >= Mnemonic.RTDG) _rtdg();
+ else if (opcode >= Mnemonic.ALIGNRP) _alignrp();
+ else if (opcode >= Mnemonic.IP) _ip();
+ else if (opcode >= Mnemonic.MSIRP) _msirp((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SHPIX) _shpix();
+ else if (opcode >= Mnemonic.SHZ) _shz((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SHC) _shc((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SHP) _shp((short)(opcode & 1));
+ else if (opcode >= Mnemonic.IUP) _iup((short)(opcode & 1));
+ else if (opcode >= Mnemonic.MDAP) _mdap((short)(opcode & 1));
+ else if (opcode >= Mnemonic.ENDF) return;
+ else if (opcode >= Mnemonic.FDEF) _fdef(ip + 1);
+ else if (opcode >= Mnemonic.CALL) _call();
+ else if (opcode >= Mnemonic.LOOPCALL) _loopcall();
+ else if (opcode >= Mnemonic.UTP) _utp();
+ else if (opcode >= Mnemonic.ALIGNPTS) _alignpts();
+ else if (opcode >= Mnemonic.MINDEX) _mindex();
+ else if (opcode >= Mnemonic.CINDEX) _cindex();
+ else if (opcode >= Mnemonic.DEPTH) _depth();
+ else if (opcode >= Mnemonic.SWAP) _swap();
+ else if (opcode >= Mnemonic.CLEAR) _clear();
+ else if (opcode >= Mnemonic.POP) pop();
+ else if (opcode >= Mnemonic.DUP) _dup();
+ else if (opcode >= Mnemonic.SSW) _ssw();
+ else if (opcode >= Mnemonic.SSWCI) _sswci();
+ else if (opcode >= Mnemonic.SCVTCI) _scvtci();
+ else if (opcode >= Mnemonic.JMPR) ip = _jmpr(ip);
+ else if (opcode >= Mnemonic.ELSE) ip = _else(ip);
+ else if (opcode >= Mnemonic.SMD) _smd();
+ else if (opcode >= Mnemonic.RTHG) _rthg();
+ else if (opcode >= Mnemonic.RTG) _rtg();
+ else if (opcode >= Mnemonic.SLOOP) _sloop();
+ else if (opcode >= Mnemonic.SZPS) _szps();
+ else if (opcode >= Mnemonic.SZP2) _szp2();
+ else if (opcode >= Mnemonic.SZP1) _szp1();
+ else if (opcode >= Mnemonic.SZP0) _szp0();
+ else if (opcode >= Mnemonic.SRP2) _srp2();
+ else if (opcode >= Mnemonic.SRP1) _srp1();
+ else if (opcode >= Mnemonic.SRP0) _srp0();
+ else if (opcode >= Mnemonic.ISECT) _isect();
+ else if (opcode >= Mnemonic.SFVTPV) _sfvtpv();
+ else if (opcode >= Mnemonic.GFV) _gfv();
+ else if (opcode >= Mnemonic.GPV) _gpv();
+ else if (opcode >= Mnemonic.SFVFS) _sfvfs();
+ else if (opcode >= Mnemonic.SPVFS) _spvfs();
+ else if (opcode >= Mnemonic.SFVTL) _sfvtl((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SPVTL) _spvtl((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SFVTCA) _sfvtca((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SPVTCA) _spvtca((short)(opcode & 1));
+ else if (opcode >= Mnemonic.SVTCA) _svtca((short)(opcode & 1));
+ ip = parser.advanceIP(ip);
+ }
+ }
+
+ public Point[][] getZones() {
+ return zone;
+ }
+
+ private int pop() {
+ return stack[--stackIndex];
+ }
+
+ private void push(int i) {
+ stack[stackIndex++] = i;
+ }
+
+ public void runCvtProgram() {
+ execute(0x00010000);
+ }
+
+ public void runFontProgram() {
+ execute(0);
+ }
+
+ public void runGlyphProgram() {
+ // instruction_control can be set to stop glyphs grid-fitting
+ if ((gs.instruction_control & 1) == 0) {
+ execute(0x00020000);
+ }
+ }
+
+ public void setParser(Parser p) {
+ parser = p;
+ }
+}
diff --git a/src/typecast/net/java/dev/typecast/tt/engine/Parser.java b/src/typecast/net/java/dev/typecast/tt/engine/Parser.java
new file mode 100644
index 000000000..bfae53197
--- /dev/null
+++ b/src/typecast/net/java/dev/typecast/tt/engine/Parser.java
@@ -0,0 +1,192 @@
+/*
+ * $Id: Parser.java,v 1.1.1.1 2004-12-05 23:15:06 davidsch Exp $
+ *
+ * Typecast - The Font Development Environment
+ *
+ * Copyright (c) 2004 David Schweinsberg
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.java.dev.typecast.tt.engine;
+
+import net.java.dev.typecast.ot.Mnemonic;
+
+/**
+ * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a>
+ * @version $Id: Parser.java,v 1.1.1.1 2004-12-05 23:15:06 davidsch Exp $
+ */
+public class Parser {
+
+ private short[][] instructions = new short[3][];
+
+ /**
+ * Advance the instruction pointer to the next executable opcode.
+ * This will be the next byte, unless the current opcode is a push
+ * instruction, in which case it will be the byte immediately beyond
+ * the last data byte.
+ * @param ip The current instruction pointer
+ * @return The new instruction pointer
+ */
+ public int advanceIP(int ip) {
+
+ // The high word specifies font, cvt, or glyph program
+ int prog = ip >> 16;
+ int i = ip & 0xffff;
+ int dataCount;
+ ip++;
+ if (Mnemonic.NPUSHB == instructions[prog][i]) {
+ // Next byte is the data byte count
+ dataCount = instructions[prog][++i];
+ ip += dataCount + 1;
+ } else if (Mnemonic.NPUSHW == instructions[prog][i]) {
+ // Next byte is the data word count
+ dataCount = instructions[prog][++i];
+ ip += dataCount*2 + 1;
+ } else if (Mnemonic.PUSHB == (instructions[prog][i] & 0xf8)) {
+ dataCount = (short)((instructions[prog][i] & 0x07) + 1);
+ ip += dataCount;
+ } else if (Mnemonic.PUSHW == (instructions[prog][i] & 0xf8)) {
+ dataCount = (short)((instructions[prog][i] & 0x07) + 1);
+ ip += dataCount*2;
+ }
+ return ip;
+ }
+
+ public int getISLength(int prog) {
+ return instructions[prog].length;
+ }
+
+ public short getOpcode(int ip) {
+ return instructions[ip >> 16][ip & 0xffff];
+ }
+
+ public short getPushCount(int ip) {
+ short instr = instructions[ip >> 16][ip & 0xffff];
+ if ((Mnemonic.NPUSHB == instr) || (Mnemonic.NPUSHW == instr)) {
+ return instructions[ip >> 16][(ip & 0xffff) + 1];
+ } else if ((Mnemonic.PUSHB == (instr & 0xf8)) || (Mnemonic.PUSHW == (instr & 0xf8))) {
+ return (short)((instr & 0x07) + 1);
+ }
+ return 0;
+ }
+
+ public int[] getPushData(int ip) {
+ int count = getPushCount(ip);
+ int[] data = new int[count];
+ int prog = ip >> 16;
+ int i = ip & 0xffff;
+ short instr = instructions[prog][i];
+ if (Mnemonic.NPUSHB == instr) {
+ for (int j = 0; j < count; j++) {
+ data[j] = instructions[prog][i + j + 2];
+ }
+ } else if (Mnemonic.PUSHB == (instr & 0xf8)) {
+ for (int j = 0; j < count; j++) {
+ data[j] = instructions[prog][i + j + 1];
+ }
+ } else if (Mnemonic.NPUSHW == instr) {
+ for (int j = 0; j < count; j++) {
+ data[j] = (instructions[prog][i + j*2 + 2] << 8) | instructions[prog][i + j*2 + 3];
+ }
+ } else if (Mnemonic.PUSHW == (instr & 0xf8)) {
+ for (int j = 0; j < count; j++) {
+ data[j] = (instructions[prog][i + j*2 + 1] << 8) | instructions[prog][i + j*2 + 2];
+ }
+ }
+ return data;
+ }
+
+ public int handleElse(int ip) {
+ while (instructions[ip >> 16][ip & 0xffff] != Mnemonic.EIF) {
+ ip = advanceIP(ip);
+ }
+ return ip;
+ }
+
+ public int handleIf(boolean test, int ip) {
+ if (test == false) {
+ // The TrueType spec says that we merely jump to the *next* ELSE or EIF
+ // instruction in the instruction stream. So therefore no nesting!
+ // Looking at actual code, IF-ELSE-EIF can be nested!
+ while ((instructions[ip >> 16][ip & 0xffff] != Mnemonic.ELSE)
+ && (instructions[ip >> 16][ip & 0xffff] != Mnemonic.EIF)) {
+ ip = advanceIP(ip);
+ }
+ }
+ return ip;
+ }
+
+ /**
+ * This program is run everytime we scale the font
+ */
+ public void setCvtProgram(short[] program) {
+ instructions[1] = program;
+ }
+
+ /**
+ * This program is only run once
+ */
+ public void setFontProgram(short[] program) {
+ instructions[0] = program;
+ }
+
+ /**
+ * This program is run everytime we scale the glyph
+ */
+ public void setGlyphProgram(short[] program) {
+ instructions[2] = program;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ int ip = 0;
+ while (ip < instructions[0].length) {
+ sb.append(Mnemonic.getMnemonic(getOpcode(ip)));
+ if (getPushCount(ip) > 0) {
+ int[] data = getPushData(ip);
+ for(int j = 0; j < data.length; j++)
+ sb.append(" ").append(data[j]);
+ }
+ sb.append("\n");
+ ip = advanceIP(ip);
+ }
+ sb.append("\n");
+ ip = 0x10000;
+ while (ip < (0x10000 | instructions[1].length)) {
+ sb.append(Mnemonic.getMnemonic(getOpcode(ip)));
+ if(getPushCount(ip) > 0) {
+ int[] data = getPushData(ip);
+ for (int j = 0; j < data.length; j++) {
+ sb.append(" ").append(data[j]);
+ }
+ }
+ sb.append("\n");
+ ip = advanceIP(ip);
+ }
+ sb.append("\n");
+ ip = 0x20000;
+ while (ip < (0x20000 | instructions[2].length)) {
+ sb.append(Mnemonic.getMnemonic(getOpcode(ip)));
+ if (getPushCount(ip) > 0) {
+ int[] data = getPushData(ip);
+ for (int j = 0; j < data.length; j++) {
+ sb.append(" ").append(data[j]);
+ }
+ }
+ sb.append("\n");
+ ip = advanceIP(ip);
+ }
+ return sb.toString();
+ }
+}