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