1 /**
2  * Copyright 2011 JogAmp Community. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  *    1. Redistributions of source code must retain the above copyright notice, this list of
8  *       conditions and the following disclaimer.
9  *
10  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *       of conditions and the following disclaimer in the documentation and/or other materials
12  *       provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  * or implied, of JogAmp Community.
27  */
28 package jogamp.graph.font.typecast;
29 
30 import com.jogamp.common.util.IntIntHashMap;
31 import com.jogamp.graph.curve.OutlineShape;
32 import com.jogamp.graph.font.Font;
33 import com.jogamp.opengl.math.geom.AABBox;
34 
35 public final class TypecastGlyph implements Font.Glyph {
36     public static final class Advance
37     {
38         private final Font      font;
39         private final float     advance;
40         private final IntIntHashMap size2advanceI = new IntIntHashMap();
41 
Advance(final Font font, final float advance)42         public Advance(final Font font, final float advance)
43         {
44             this.font = font;
45             this.advance = advance;
46             size2advanceI.setKeyNotFoundValue(0);
47         }
48 
reset()49         public final void reset() {
50             size2advanceI.clear();
51         }
52 
getFont()53         public final Font getFont() { return font; }
54 
getScale(final float pixelSize)55         public final float getScale(final float pixelSize)
56         {
57             return this.font.getMetrics().getScale(pixelSize);
58         }
59 
add(final float advance, final float size)60         public final void add(final float advance, final float size)
61         {
62             size2advanceI.put(Float.floatToIntBits(size), Float.floatToIntBits(advance));
63         }
64 
get(final float pixelSize, final boolean useFrationalMetrics)65         public final float get(final float pixelSize, final boolean useFrationalMetrics)
66         {
67             final int sI = Float.floatToIntBits(pixelSize);
68             final int aI = size2advanceI.get(sI);
69             if( 0 != aI ) {
70                 return Float.intBitsToFloat(aI);
71             }
72             final float a;
73             if ( useFrationalMetrics ) {
74                 a = this.advance * getScale(pixelSize);
75             } else {
76                 // a = Math.ceil(this.advance * getScale(pixelSize));
77                 a = Math.round(this.advance * getScale(pixelSize)); // TODO: check whether ceil should be used instead?
78             }
79             size2advanceI.put(sI, Float.floatToIntBits(a));
80             return a;
81         }
82 
83         @Override
toString()84         public final String toString()
85         {
86             return "\nAdvance:"+
87                 "\n  advance: "+this.advance+
88                 "\n advances: \n"+size2advanceI;
89         }
90     }
91 
92     public static final class Metrics
93     {
94         private final AABBox    bbox;
95         private final Advance advance;
96 
Metrics(final Font font, final AABBox bbox, final float advance)97         public Metrics(final Font font, final AABBox bbox, final float advance)
98         {
99             this.bbox = bbox;
100             this.advance = new Advance(font, advance);
101         }
102 
reset()103         public final void reset() {
104             advance.reset();
105         }
106 
getFont()107         public final Font getFont() { return advance.getFont(); }
108 
getScale(final float pixelSize)109         public final float getScale(final float pixelSize)
110         {
111             return this.advance.getScale(pixelSize);
112         }
113 
getBBox()114         public final AABBox getBBox()
115         {
116             return this.bbox;
117         }
118 
addAdvance(final float advance, final float size)119         public final void addAdvance(final float advance, final float size)
120         {
121             this.advance.add(advance, size);
122         }
123 
getAdvance(final float pixelSize, final boolean useFrationalMetrics)124         public final float getAdvance(final float pixelSize, final boolean useFrationalMetrics)
125         {
126             return this.advance.get(pixelSize, useFrationalMetrics);
127         }
128 
129         @Override
toString()130         public final String toString()
131         {
132             return "\nMetrics:"+
133                 "\n  bbox: "+this.bbox+
134                 this.advance;
135         }
136     }
137 
138     public static final short INVALID_ID    = (short)((1 << 16) - 1);
139     public static final short MAX_ID        = (short)((1 << 16) - 2);
140 
141     private final char symbol;
142     private final OutlineShape shape; // in EM units
143     private final short id;
144     private final Metrics metrics;
145 
TypecastGlyph(final Font font, final char symbol, final short id, final AABBox bbox, final int advance, final OutlineShape shape)146     protected TypecastGlyph(final Font font, final char symbol, final short id, final AABBox bbox, final int advance, final OutlineShape shape) {
147         this.symbol = symbol;
148         this.shape = shape;
149         this.id = id;
150         this.metrics = new Metrics(font, bbox, advance);
151     }
152 
153     @Override
getFont()154     public final Font getFont() {
155         return this.metrics.getFont();
156     }
157 
158     @Override
getSymbol()159     public final char getSymbol() {
160         return this.symbol;
161     }
162 
getBBoxUnsized()163     final AABBox getBBoxUnsized() {
164         return this.metrics.getBBox();
165     }
166 
167     @Override
getBBox()168     public final AABBox getBBox() {
169         return this.metrics.getBBox();
170     }
171 
getMetrics()172     public final Metrics getMetrics() {
173         return this.metrics;
174     }
175 
176     @Override
getID()177     public final short getID() {
178         return this.id;
179     }
180 
181     @Override
getScale(final float pixelSize)182     public final float getScale(final float pixelSize) {
183         return this.metrics.getScale(pixelSize);
184     }
185 
186     @Override
getBBox(final AABBox dest, final float pixelSize, final float[] tmpV3)187     public final AABBox getBBox(final AABBox dest, final float pixelSize, final float[] tmpV3) {
188         return dest.copy(getBBox()).scale(getScale(pixelSize), tmpV3);
189     }
190 
addAdvance(final float advance, final float size)191     protected final void addAdvance(final float advance, final float size) {
192         this.metrics.addAdvance(advance, size);
193     }
194 
195     @Override
getAdvance(final float pixelSize, final boolean useFrationalMetrics)196     public final float getAdvance(final float pixelSize, final boolean useFrationalMetrics) {
197         return this.metrics.getAdvance(pixelSize, useFrationalMetrics);
198     }
199 
200     @Override
getShape()201     public final OutlineShape getShape() {
202         return this.shape;
203     }
204 
205     @Override
hashCode()206     public final int hashCode() {
207         // 31 * x == (x << 5) - x
208         final int hash = 31 + getFont().getName(Font.NAME_UNIQUNAME).hashCode();
209         return ((hash << 5) - hash) + id;
210     }
211 }
212