38 |
|
|
39 |
package gnu.java.awt.peer.gtk; |
package gnu.java.awt.peer.gtk; |
40 |
|
|
|
import gnu.classpath.Configuration; |
|
|
|
|
41 |
import java.awt.Font; |
import java.awt.Font; |
42 |
import java.awt.Rectangle; |
import java.awt.Rectangle; |
43 |
import java.awt.Shape; |
import java.awt.Shape; |
52 |
public class GdkGlyphVector extends GlyphVector |
public class GdkGlyphVector extends GlyphVector |
53 |
{ |
{ |
54 |
|
|
55 |
static |
/* We use a simple representation for glyph vectors here. Glyph i |
56 |
|
* consumes 8 doubles: |
57 |
|
* |
58 |
|
* logical x: extents[ 10*i ] |
59 |
|
* logical y: extents[ 10*i + 1 ] |
60 |
|
* logical width: extents[ 10*i + 2 ] |
61 |
|
* logical height: extents[ 10*i + 3 ] |
62 |
|
* |
63 |
|
* visual x: extents[ 10*i + 4 ] |
64 |
|
* visual y: extents[ 10*i + 5 ] |
65 |
|
* visual width: extents[ 10*i + 6 ] |
66 |
|
* visual height: extents[ 10*i + 7 ] |
67 |
|
* |
68 |
|
* origin pos x: extents[ 10*i + 8 ] |
69 |
|
* origin pos y: extents[ 10*i + 9 ] |
70 |
|
* |
71 |
|
* as well as one int, code[i], representing the glyph code in the font. |
72 |
|
*/ |
73 |
|
|
74 |
|
double [] extents; |
75 |
|
int [] codes; |
76 |
|
|
77 |
|
Font font; |
78 |
|
FontRenderContext fontRenderContext; |
79 |
|
|
80 |
|
Rectangle2D allLogical; |
81 |
|
Rectangle2D allVisual; |
82 |
|
|
83 |
|
public GdkGlyphVector(double[] extents, int[] codes, Font font, FontRenderContext frc) |
84 |
{ |
{ |
85 |
if (Configuration.INIT_LOAD_LIBRARY) |
this.extents = extents; |
86 |
|
this.codes = codes; |
87 |
|
this.font = font; |
88 |
|
this.fontRenderContext = frc; |
89 |
|
|
90 |
|
allLogical = new Rectangle2D.Double(); |
91 |
|
allVisual = new Rectangle2D.Double(); |
92 |
|
|
93 |
|
for (int i = 0; i < codes.length; ++i) |
94 |
{ |
{ |
95 |
System.loadLibrary("gtkpeer"); |
allLogical.add (new Rectangle2D.Double(extents[10*i ] + extents[10*i + 8], |
96 |
|
extents[10*i + 1] + extents[10*i + 9], |
97 |
|
extents[10*i + 2], |
98 |
|
extents[10*i + 3])); |
99 |
|
|
100 |
|
allVisual.add (new Rectangle2D.Double(extents[10*i + 4] + extents[10*i + 8], |
101 |
|
extents[10*i + 5] + extents[10*i + 9], |
102 |
|
extents[10*i + 6], |
103 |
|
extents[10*i + 7])); |
104 |
} |
} |
|
|
|
|
if (GtkToolkit.useGraphics2D ()) |
|
|
initStaticState (); |
|
105 |
} |
} |
|
native static void initStaticState (); |
|
|
private final int native_state = GtkGenericPeer.getUniqueInteger (); |
|
|
|
|
|
private Font font; |
|
|
private FontRenderContext ctx; |
|
|
|
|
|
private native void initState (GdkFontPeer peer, FontRenderContext ctx); |
|
|
private native void setChars (String s); |
|
|
private native void setGlyphCodes (int codes[]); |
|
|
private native void dispose (); |
|
|
private native int glyphCode (int idx); |
|
|
private native int numGlyphs (); |
|
|
private native int glyphCharIndex (int idx); |
|
|
private native double[] allLogicalExtents (); |
|
|
private native double[] allInkExtents (); |
|
|
private native double[] glyphLogicalExtents (int idx); |
|
|
private native double[] glyphInkExtents (int idx); |
|
|
private native boolean glyphIsHorizontal (int idx); |
|
|
private native boolean isEqual (GdkGlyphVector ggv); |
|
|
|
|
106 |
|
|
107 |
/* |
/* |
108 |
geometric notes: |
geometric notes: |
127 |
|
|
128 |
*/ |
*/ |
129 |
|
|
130 |
|
public double[] getExtents() |
|
public GdkGlyphVector (Font f, GdkFontPeer peer, FontRenderContext c, String s) |
|
131 |
{ |
{ |
132 |
font = f; |
return extents; |
|
ctx = c; |
|
|
initState (peer, ctx); |
|
|
setChars (s); |
|
133 |
} |
} |
134 |
|
|
135 |
public GdkGlyphVector (Font f, GdkFontPeer peer, FontRenderContext c, int codes[]) |
public int[] getCodes() |
136 |
{ |
{ |
137 |
font = f; |
return codes; |
|
ctx = c; |
|
|
initState (peer, ctx); |
|
|
setGlyphCodes (codes); |
|
|
} |
|
|
|
|
|
protected void finalize () |
|
|
{ |
|
|
dispose (); |
|
138 |
} |
} |
139 |
|
|
140 |
public Font getFont () |
public Font getFont () |
144 |
|
|
145 |
public FontRenderContext getFontRenderContext () |
public FontRenderContext getFontRenderContext () |
146 |
{ |
{ |
147 |
return ctx; |
return fontRenderContext; |
148 |
} |
} |
149 |
|
|
150 |
public int getGlyphCharIndex (int glyphIndex) |
public int getGlyphCharIndex (int glyphIndex) |
151 |
{ |
{ |
152 |
return glyphCharIndex (glyphIndex); |
// FIXME: currently pango does not provide glyph-by-glyph |
153 |
|
// reverse mapping information, so we assume a broken 1:1 |
154 |
|
// glyph model here. This is plainly wrong. |
155 |
|
return glyphIndex; |
156 |
} |
} |
157 |
|
|
158 |
public int[] getGlyphCharIndices (int beginGlyphIndex, |
public int[] getGlyphCharIndices (int beginGlyphIndex, |
164 |
ix = new int[numEntries]; |
ix = new int[numEntries]; |
165 |
|
|
166 |
for (int i = 0; i < numEntries; i++) |
for (int i = 0; i < numEntries; i++) |
167 |
ix[i] = glyphCharIndex (beginGlyphIndex + i); |
ix[i] = getGlyphCharIndex (beginGlyphIndex + i); |
168 |
return ix; |
return ix; |
169 |
} |
} |
170 |
|
|
171 |
public int getGlyphCode (int glyphIndex) |
public int getGlyphCode (int glyphIndex) |
172 |
{ |
{ |
173 |
return glyphCode (glyphIndex); |
return codes[glyphIndex]; |
174 |
} |
} |
175 |
|
|
176 |
public int[] getGlyphCodes (int beginGlyphIndex, int numEntries, |
public int[] getGlyphCodes (int beginGlyphIndex, int numEntries, |
177 |
int[] codeReturn) |
int[] codeReturn) |
178 |
{ |
{ |
179 |
int ix[] = codeReturn; |
if (codeReturn == null) |
180 |
if (ix == null) |
codeReturn = new int[numEntries]; |
|
ix = new int[numEntries]; |
|
181 |
|
|
182 |
for (int i = 0; i < numEntries; i++) |
System.arraycopy(codes, beginGlyphIndex, codeReturn, 0, numEntries); |
183 |
ix[i] = glyphCode (beginGlyphIndex + i); |
return codeReturn; |
|
return ix; |
|
184 |
} |
} |
185 |
|
|
186 |
public Shape getGlyphLogicalBounds (int glyphIndex) |
public Shape getGlyphLogicalBounds (int i) |
187 |
{ |
{ |
188 |
double extents[] = glyphLogicalExtents (glyphIndex); |
return new Rectangle2D.Double (extents[8*i], extents[8*i + 1], |
189 |
return new Rectangle2D.Double (extents[0], extents[1], |
extents[8*i + 2], extents[8*i + 3]); |
|
extents[2], extents[3]); |
|
190 |
} |
} |
191 |
|
|
192 |
public GlyphMetrics getGlyphMetrics (int glyphIndex) |
public GlyphMetrics getGlyphMetrics (int i) |
193 |
{ |
{ |
194 |
double extents[] = glyphLogicalExtents (glyphIndex); |
// FIXME: pango does not yield vertical layout information at the |
195 |
Rectangle2D log_bounds = new Rectangle2D.Double (extents[0], extents[1], |
// moment. |
196 |
extents[2], extents[3]); |
|
197 |
|
boolean is_horizontal = true; |
198 |
extents = glyphInkExtents (glyphIndex); |
double advanceX = extents[8*i + 2]; // "logical width" == advanceX |
199 |
Rectangle2D ink_bounds = new Rectangle2D.Double (extents[0], extents[1], |
double advanceY = 0; |
200 |
extents[2], extents[3]); |
|
201 |
|
return new GlyphMetrics (is_horizontal, |
202 |
boolean is_horizontal = glyphIsHorizontal (glyphIndex); |
(float) advanceX, (float) advanceY, |
203 |
|
(Rectangle2D) getGlyphVisualBounds(i), |
204 |
return new GlyphMetrics (is_horizontal, |
GlyphMetrics.STANDARD); |
|
(float)(log_bounds.getWidth() + log_bounds.getX()), |
|
|
(float)(log_bounds.getHeight() + log_bounds.getY()), |
|
|
ink_bounds, GlyphMetrics.STANDARD); |
|
205 |
} |
} |
206 |
|
|
207 |
public Shape getGlyphOutline (int glyphIndex) |
public Shape getGlyphOutline (int glyphIndex) |
214 |
throw new UnsupportedOperationException (); |
throw new UnsupportedOperationException (); |
215 |
} |
} |
216 |
|
|
217 |
public Rectangle getGlyphPixelBounds (int glyphIndex, |
public Rectangle getGlyphPixelBounds (int i, |
218 |
FontRenderContext renderFRC, |
FontRenderContext renderFRC, |
219 |
float x, float y) |
float x, float y) |
220 |
{ |
{ |
221 |
double extents[] = glyphInkExtents(glyphIndex); |
return new Rectangle((int) x, (int) y, |
222 |
return new Rectangle ((int)x, (int)y, (int)extents[2], (int)extents[3]); |
(int) extents[8*i + 6], (int) extents[8*i + 7]); |
223 |
} |
} |
224 |
|
|
225 |
public Point2D getGlyphPosition (int glyphIndex) |
public Point2D getGlyphPosition (int i) |
226 |
{ |
{ |
227 |
float[] ret = new float[2 * (glyphIndex + 1)]; |
return new Point2D.Double (extents[10*i + 8], |
228 |
getGlyphPositions (0, glyphIndex + 1, ret); |
extents[10*i + 9]); |
|
return new Point2D.Float (ret[2 * glyphIndex], |
|
|
ret[2 * glyphIndex + 1]); |
|
229 |
} |
} |
230 |
|
|
231 |
public float[] getGlyphPositions (int beginGlyphIndex, |
public float[] getGlyphPositions (int beginGlyphIndex, |
236 |
if (fx == null) |
if (fx == null) |
237 |
fx = new float[numEntries * 2]; |
fx = new float[numEntries * 2]; |
238 |
|
|
|
|
|
|
float x = 0.0f; |
|
|
float y = 0.0f; |
|
239 |
for (int i = 0; i < numEntries; ++i) |
for (int i = 0; i < numEntries; ++i) |
240 |
{ |
{ |
241 |
boolean is_horizontal = glyphIsHorizontal (beginGlyphIndex + i); |
fx[2*i ] = (float) extents[10*i + 8]; |
242 |
double log_extents[] = glyphLogicalExtents (beginGlyphIndex + i); |
fx[2*i + 1] = (float) extents[10*i + 9]; |
|
fx[2*i] = x + (float)log_extents[0]; // x offset |
|
|
fx[2*i + 1] = y + (float)log_extents[1]; // y offset |
|
|
if (is_horizontal) |
|
|
x += (float)log_extents[2]; // x advance ("logical width") in pango-ese |
|
|
else |
|
|
y += (float)log_extents[3]; // y advance ("logical height") in pango-ese |
|
243 |
} |
} |
244 |
return fx; |
return fx; |
245 |
} |
} |
246 |
|
|
247 |
public AffineTransform getGlyphTransform (int glyphIndex) |
public AffineTransform getGlyphTransform (int glyphIndex) |
248 |
{ |
{ |
249 |
// glyphs don't have independent transforms in these simple glyph |
// Glyphs don't have independent transforms in these simple glyph |
250 |
// vectors; docs specify null is an ok return here. |
// vectors; docs specify null is an ok return here. |
251 |
return null; |
return null; |
252 |
} |
} |
253 |
|
|
254 |
public Shape getGlyphVisualBounds (int glyphIndex) |
public Shape getGlyphVisualBounds (int i) |
255 |
{ |
{ |
256 |
double extents[] = glyphInkExtents (glyphIndex); |
return new Rectangle2D.Double(extents[8*i + 4], extents[8*i + 5], |
257 |
return new Rectangle2D.Double (extents[0], extents[1], |
extents[8*i + 6], extents[8*i + 7]); |
|
extents[2], extents[3]); |
|
258 |
} |
} |
259 |
|
|
260 |
public int getLayoutFlags () |
public int getLayoutFlags () |
264 |
|
|
265 |
public Rectangle2D getLogicalBounds () |
public Rectangle2D getLogicalBounds () |
266 |
{ |
{ |
267 |
double extents[] = allLogicalExtents (); |
return allLogical; |
|
return new Rectangle2D.Double (extents[0], extents[1], |
|
|
extents[2], extents[3]); |
|
268 |
} |
} |
269 |
|
|
270 |
public int getNumGlyphs () |
public int getNumGlyphs () |
271 |
{ |
{ |
272 |
return numGlyphs (); |
return codes.length; |
273 |
} |
} |
274 |
|
|
275 |
public Shape getOutline () |
public Shape getOutline () |
280 |
public Rectangle getPixelBounds (FontRenderContext renderFRC, |
public Rectangle getPixelBounds (FontRenderContext renderFRC, |
281 |
float x, float y) |
float x, float y) |
282 |
{ |
{ |
283 |
double extents[] = allInkExtents(); |
return new Rectangle((int)x, |
284 |
return new Rectangle ((int)x, (int)y, |
(int)y, |
285 |
(int)extents[2], (int)extents[3]); |
(int) allVisual.getWidth(), |
286 |
|
(int) allVisual.getHeight()); |
287 |
} |
} |
288 |
|
|
289 |
public Rectangle2D getVisualBounds () |
public Rectangle2D getVisualBounds () |
290 |
{ |
{ |
291 |
double extents[] = allInkExtents(); |
return allVisual; |
|
return new Rectangle2D.Double (extents[0], extents[1], |
|
|
extents[2], extents[3]); |
|
292 |
} |
} |
293 |
|
|
294 |
public void performDefaultLayout () |
public void performDefaultLayout () |
295 |
{ |
{ |
296 |
} |
} |
297 |
|
|
298 |
public void setGlyphPosition (int glyphIndex, Point2D newPos) |
public void setGlyphPosition (int i, Point2D newPos) |
299 |
{ |
{ |
300 |
// should we be ok twiddling pango's structure here? |
extents[8*i ] = newPos.getX(); |
301 |
throw new UnsupportedOperationException (); |
extents[8*i + 1] = newPos.getY(); |
302 |
|
|
303 |
|
extents[8*i + 4] = newPos.getX(); |
304 |
|
extents[8*i + 5] = newPos.getY(); |
305 |
} |
} |
306 |
|
|
307 |
public void setGlyphTransform (int glyphIndex, |
public void setGlyphTransform (int glyphIndex, |
319 |
if (! (gv instanceof GdkGlyphVector)) |
if (! (gv instanceof GdkGlyphVector)) |
320 |
return false; |
return false; |
321 |
|
|
322 |
GdkGlyphVector ggv = (GdkGlyphVector)gv; |
GdkGlyphVector ggv = (GdkGlyphVector) gv; |
323 |
return isEqual(ggv); |
|
324 |
|
if ((ggv.codes.length != this.codes.length) |
325 |
|
|| (ggv.extents.length != this.extents.length)) |
326 |
|
return false; |
327 |
|
|
328 |
|
if ((ggv.font == null && this.font != null) |
329 |
|
|| (ggv.font != null && this.font == null) |
330 |
|
|| (!ggv.font.equals(this.font))) |
331 |
|
return false; |
332 |
|
|
333 |
|
if ((ggv.fontRenderContext == null && this.fontRenderContext != null) |
334 |
|
|| (ggv.fontRenderContext != null && this.fontRenderContext == null) |
335 |
|
|| (!ggv.fontRenderContext.equals(this.fontRenderContext))) |
336 |
|
return false; |
337 |
|
|
338 |
|
for (int i = 0; i < ggv.codes.length; ++i) |
339 |
|
if (ggv.codes[i] != this.codes[i]) |
340 |
|
return false; |
341 |
|
|
342 |
|
for (int i = 0; i < ggv.extents.length; ++i) |
343 |
|
if (ggv.extents[i] != this.extents[i]) |
344 |
|
return false; |
345 |
|
|
346 |
|
return true; |
347 |
} |
} |
348 |
|
|
349 |
public GlyphJustificationInfo getGlyphJustificationInfo(int idx) |
public GlyphJustificationInfo getGlyphJustificationInfo(int idx) |