aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.4.3/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.4.3/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java')
-rw-r--r--gcc-4.4.3/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java630
1 files changed, 630 insertions, 0 deletions
diff --git a/gcc-4.4.3/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/gcc-4.4.3/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
new file mode 100644
index 000000000..af975f394
--- /dev/null
+++ b/gcc-4.4.3/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
@@ -0,0 +1,630 @@
+/* FreetypeGlyphVector.java
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.awt.peer.gtk;
+
+import java.awt.Font;
+import java.awt.Shape;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphJustificationInfo;
+import java.awt.font.GlyphMetrics;
+import java.awt.font.GlyphVector;
+import java.awt.font.TextAttribute;
+import java.awt.font.TransformAttribute;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Arrays;
+
+public class FreetypeGlyphVector extends GlyphVector
+{
+ /**
+ * The associated font and its peer.
+ */
+ private Font font;
+ private GdkFontPeer peer; // ATTN: Accessed from native code.
+
+ private Rectangle2D logicalBounds;
+
+ private float[] glyphPositions;
+ /**
+ * The string represented by this GlyphVector.
+ */
+ private String s;
+
+ /**
+ * The font render context
+ */
+ private FontRenderContext frc;
+
+ /**
+ * The total # of glyphs.
+ */
+ private int nGlyphs;
+
+ /**
+ * The glyph codes
+ */
+ private int[] glyphCodes;
+
+ /**
+ * The set of fonts used in this glyph vector.
+ */
+ private long[] fontSet = null;
+
+ /**
+ * Glyph transforms. Supports all transform operations.
+ *
+ * The identity transform should not be stored in this array; use a null
+ * instead (will result in performance improvements).
+ */
+ private AffineTransform[] glyphTransforms;
+
+ private GlyphMetrics[] metricsCache;
+
+ private native void dispose(long[] fonts);
+
+ /**
+ * Returns a pointer to the native PangoFcFont object.
+ *
+ * The object will be referenced with g_object_ref n times before being
+ * returned, and must be unreferenced a corresponding number of times.
+ *
+ * @param n Number of times to reference the object.
+ * @return Pointer to the native default font.
+ */
+ private native long getNativeFontPointer(int n);
+
+ /**
+ * Create a glyphvector from a given (Freetype) font and a String.
+ */
+ public FreetypeGlyphVector(Font f, String s, FontRenderContext frc)
+ {
+ this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT);
+ }
+
+ /**
+ * Create a glyphvector from a given (Freetype) font and a String.
+ */
+ public FreetypeGlyphVector(Font f, char[] chars, int start, int len,
+ FontRenderContext frc, int flags)
+ {
+ this.s = new String(chars, start, len);
+
+ this.font = f;
+ this.frc = frc;
+ if( !(font.getPeer() instanceof GdkFontPeer ) )
+ throw new IllegalArgumentException("Not a valid font.");
+ peer = (GdkFontPeer)font.getPeer();
+
+ getGlyphs();
+ if( flags == Font.LAYOUT_RIGHT_TO_LEFT )
+ {
+ // reverse the glyph ordering.
+ int[] temp = new int[ nGlyphs ];
+ for(int i = 0; i < nGlyphs; i++)
+ temp[i] = glyphCodes[nGlyphs - i - 1];
+ glyphCodes = temp;
+ }
+ performDefaultLayout();
+ }
+
+ /**
+ * Create a glyphvector from a given set of glyph codes.
+ */
+ public FreetypeGlyphVector(Font f, int[] codes, FontRenderContext frc)
+ {
+ this.font = f;
+ this.frc = frc;
+ if( !(font.getPeer() instanceof GdkFontPeer ) )
+ throw new IllegalArgumentException("Not a valid font.");
+ peer = (GdkFontPeer)font.getPeer();
+
+ glyphCodes = new int[ codes.length ];
+ System.arraycopy(codes, 0, glyphCodes, 0, codes.length);
+ nGlyphs = glyphCodes.length;
+
+ if (fontSet == null)
+ {
+ fontSet = new long[nGlyphs];
+ Arrays.fill(fontSet, getNativeFontPointer(nGlyphs));
+ }
+
+ performDefaultLayout();
+ }
+
+ /**
+ * Cloning constructor
+ */
+ private FreetypeGlyphVector( FreetypeGlyphVector gv )
+ {
+ font = gv.font;
+ peer = gv.peer;
+ frc = gv.frc;
+ s = gv.s;
+ nGlyphs = gv.nGlyphs;
+ logicalBounds = gv.logicalBounds.getBounds2D();
+
+ if( gv.metricsCache != null )
+ {
+ metricsCache = new GlyphMetrics[ nGlyphs ];
+ System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs);
+ }
+
+ glyphCodes = new int[ nGlyphs ];
+ fontSet = new long[nGlyphs];
+ glyphPositions = new float[(nGlyphs + 1) * 2];
+ glyphTransforms = new AffineTransform[ nGlyphs ];
+ Arrays.fill(glyphTransforms, null);
+
+ for(int i = 0; i < nGlyphs; i++ )
+ {
+ if (gv.glyphTransforms[i] != null)
+ glyphTransforms[ i ] = new AffineTransform(gv.glyphTransforms[i]);
+ glyphCodes[i] = gv.glyphCodes[ i ];
+ }
+ System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0,
+ glyphPositions.length);
+ System.arraycopy(gv.glyphCodes, 0, glyphCodes, 0, nGlyphs);
+ System.arraycopy(gv.fontSet, 0, fontSet, 0, nGlyphs);
+ }
+
+ public void finalize()
+ {
+ dispose(fontSet);
+ }
+
+ /**
+ * Create the array of glyph codes.
+ */
+ private void getGlyphs()
+ {
+ nGlyphs = s.codePointCount( 0, s.length() );
+ glyphCodes = new int[ nGlyphs ];
+ fontSet = new long[ nGlyphs ];
+ int[] codePoints = new int[ nGlyphs ];
+ int stringIndex = 0;
+
+ for(int i = 0; i < nGlyphs; i++)
+ {
+ codePoints[i] = s.codePointAt( stringIndex );
+ // UTF32 surrogate handling
+ if( codePoints[i] != (int)s.charAt( stringIndex ) )
+ stringIndex ++;
+ stringIndex ++;
+
+ if (Character.isISOControl(codePoints[i]))
+ {
+ // Replace with 'hair space'. Should better be 'zero-width space'
+ // but that doesn't seem to be supported by default font.
+ codePoints[i] = 8202;
+ }
+ }
+
+ getGlyphs( codePoints, glyphCodes, fontSet );
+ }
+
+ /**
+ * Returns the glyph code within the font for a given character
+ */
+ public native void getGlyphs(int[] codepoints, int[] glyphs, long[] fonts);
+
+ /**
+ * Returns the kerning of a glyph pair
+ */
+ private native void getKerning(int leftGlyph, int rightGlyph, long font,
+ float[] p);
+
+ private native double[] getMetricsNative(int glyphCode, long font);
+
+ private native GeneralPath getGlyphOutlineNative(int glyphIndex, long font);
+
+
+ public Object clone()
+ {
+ return new FreetypeGlyphVector( this );
+ }
+
+ /**
+ * Duh, compares two instances.
+ */
+ public boolean equals(GlyphVector gv)
+ {
+ if( ! (gv instanceof FreetypeGlyphVector) )
+ return false;
+
+ return (((FreetypeGlyphVector)gv).font.equals(font) &&
+ ((FreetypeGlyphVector)gv).frc.equals(frc)
+ && ((FreetypeGlyphVector)gv).s.equals(s));
+ }
+
+ /**
+ * Returns the associated Font
+ */
+ public Font getFont()
+ {
+ return font;
+ }
+
+ /**
+ * Returns the associated FontRenderContext
+ */
+ public FontRenderContext getFontRenderContext()
+ {
+ return frc;
+ }
+
+ /**
+ * Layout the glyphs.
+ */
+ public void performDefaultLayout()
+ {
+ logicalBounds = null; // invalidate caches.
+ glyphTransforms = new AffineTransform[nGlyphs];
+ Arrays.fill(glyphTransforms, null);
+ glyphPositions = new float[(nGlyphs + 1) * 2];
+
+ GlyphMetrics gm = null;
+ float x = 0;
+ float y = 0;
+ float[] p = {0.0f, 0.0f};
+ for(int i = 0; i < nGlyphs; i++)
+ {
+ gm = getGlyphMetrics( i );
+ glyphPositions[i*2] = x;
+ glyphPositions[i*2 + 1] = y;
+
+ x += gm.getAdvanceX();
+ y += gm.getAdvanceY();
+
+ // Get the kerning only if it's not the last glyph, and the two glyphs are
+ // using the same font
+ if (i != nGlyphs-1 && fontSet[i] == fontSet[i+1])
+ {
+ getKerning(glyphCodes[i], glyphCodes[i + 1], fontSet[i], p);
+ x += p[0];
+ y += p[1];
+ }
+ }
+ glyphPositions[nGlyphs * 2] = x;
+ glyphPositions[nGlyphs * 2 + 1] = y;
+
+ // Apply any transform that may be in the font's attributes
+ TransformAttribute ta;
+ ta = (TransformAttribute)font.getAttributes().get(TextAttribute.TRANSFORM);
+ if (ta != null)
+ {
+ AffineTransform tx = ta.getTransform();
+
+ // Transform glyph positions
+ tx.transform(glyphPositions, 0, glyphPositions, 0,
+ glyphPositions.length / 2);
+
+ // Also store per-glyph scale/shear/rotate (but not translation)
+ double[] matrix = new double[4];
+ tx.getMatrix(matrix);
+ AffineTransform deltaTx = new AffineTransform(matrix);
+ if (!deltaTx.isIdentity())
+ Arrays.fill(glyphTransforms, deltaTx);
+ }
+ }
+
+ /**
+ * Returns the code of the glyph at glyphIndex;
+ */
+ public int getGlyphCode(int glyphIndex)
+ {
+ return glyphCodes[ glyphIndex ];
+ }
+
+ /**
+ * Returns multiple glyphcodes.
+ */
+ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
+ int[] codeReturn)
+ {
+ int[] rval;
+
+ if( codeReturn == null || codeReturn.length < numEntries)
+ rval = new int[ numEntries ];
+ else
+ rval = codeReturn;
+
+ System.arraycopy(glyphCodes, beginGlyphIndex, rval, 0, numEntries);
+
+ return rval;
+ }
+
+ /**
+ * Returns pointers to the fonts used in this glyph vector.
+ *
+ * The array index matches that of the glyph vector itself.
+ */
+ protected long[] getGlyphFonts(int beginGlyphIndex, int numEntries,
+ long[] codeReturn)
+ {
+ long[] rval;
+
+ if( codeReturn == null || codeReturn.length < numEntries)
+ rval = new long[ numEntries ];
+ else
+ rval = codeReturn;
+
+ System.arraycopy(fontSet, beginGlyphIndex, rval, 0, numEntries);
+
+ return rval;
+ }
+
+ public Shape getGlyphLogicalBounds(int glyphIndex)
+ {
+ GlyphMetrics gm = getGlyphMetrics( glyphIndex );
+ if( gm == null )
+ return null;
+ Rectangle2D r = gm.getBounds2D();
+ Point2D p = getGlyphPosition( glyphIndex );
+
+ double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(),
+ p.getY() + r.getY(),
+ p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(),
+ p.getY() + r.getY() + r.getHeight()};
+
+ if (glyphTransforms[glyphIndex] != null)
+ glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 2);
+
+ return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0],
+ bounds[3] - bounds[1]);
+ }
+
+ /*
+ * FIXME: Not all glyph types are supported.
+ * (The JDK doesn't really seem to do so either)
+ */
+ public void setupGlyphMetrics()
+ {
+ metricsCache = new GlyphMetrics[ nGlyphs ];
+
+ for(int i = 0; i < nGlyphs; i++)
+ {
+ GlyphMetrics gm = (GlyphMetrics)peer.getGlyphMetrics(glyphCodes[i]);
+ if( gm == null )
+ {
+ double[] val = getMetricsNative(glyphCodes[i], fontSet[i]);
+ if( val == null )
+ gm = null;
+ else
+ {
+ gm = new GlyphMetrics(true,
+ (float)val[1],
+ (float)val[2],
+ new Rectangle2D.Double(val[3], val[4],
+ val[5], val[6] ),
+ GlyphMetrics.STANDARD );
+ peer.putGlyphMetrics( glyphCodes[ i ], gm );
+ }
+ }
+ metricsCache[ i ] = gm;
+ }
+ }
+
+ /**
+ * Returns the metrics of a single glyph.
+ */
+ public GlyphMetrics getGlyphMetrics(int glyphIndex)
+ {
+ if( metricsCache == null )
+ setupGlyphMetrics();
+
+ return metricsCache[ glyphIndex ];
+ }
+
+ /**
+ * Returns the outline of a single glyph.
+ *
+ * Despite what the Sun API says, this method returns the glyph relative to
+ * the origin of the *entire string*, not each individual glyph.
+ */
+ public Shape getGlyphOutline(int glyphIndex)
+ {
+ GeneralPath gp = getGlyphOutlineNative(glyphCodes[glyphIndex],
+ fontSet[glyphIndex]);
+
+ AffineTransform tx = AffineTransform.getTranslateInstance(glyphPositions[glyphIndex*2],
+ glyphPositions[glyphIndex*2+1]);
+ if (glyphTransforms[glyphIndex] != null)
+ tx.concatenate( glyphTransforms[glyphIndex]);
+
+ gp.transform(tx);
+ return gp;
+ }
+
+ /**
+ * Returns the position of a single glyph.
+ */
+ public Point2D getGlyphPosition(int glyphIndex)
+ {
+ return new Point2D.Float(glyphPositions[glyphIndex*2],
+ glyphPositions[glyphIndex*2 + 1]);
+ }
+
+ /**
+ * Returns the positions of multiple glyphs.
+ */
+ public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
+ float[] positionReturn)
+ {
+ if (positionReturn == null || positionReturn.length < (numEntries * 2))
+ positionReturn = new float[numEntries*2];
+
+ System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0,
+ numEntries*2);
+ return positionReturn;
+ }
+
+ /**
+ * Returns the transform of a glyph.
+ */
+ public AffineTransform getGlyphTransform(int glyphIndex)
+ {
+ return glyphTransforms[glyphIndex];
+ }
+
+ /**
+ * Checks whether any transform has been set on any glyphs.
+ */
+ protected boolean hasTransforms()
+ {
+ for (int i = 0; i < glyphTransforms.length; i++)
+ if (glyphTransforms[i] != null)
+ return true;
+
+ return false;
+ }
+
+ /**
+ * Returns the visual bounds of a glyph
+ * May be off by a pixel or two due to hinting/rasterization.
+ */
+ public Shape getGlyphVisualBounds(int glyphIndex)
+ {
+ return getGlyphOutline( glyphIndex ).getBounds2D();
+ }
+
+ /**
+ * Return the logical bounds of the whole thing.
+ */
+ public Rectangle2D getLogicalBounds()
+ {
+ if( nGlyphs == 0 )
+ return new Rectangle2D.Double(0, 0, 0, 0);
+ if( logicalBounds != null )
+ return logicalBounds;
+
+ Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 );
+ for( int i = 1; i < nGlyphs; i++ )
+ {
+ Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
+
+ rect = rect.createUnion( r2 );
+ }
+
+ logicalBounds = rect;
+ return rect;
+ }
+
+ /**
+ * Returns the number of glyphs.
+ */
+ public int getNumGlyphs()
+ {
+ return glyphCodes.length;
+ }
+
+ /**
+ * Returns the outline of the entire GlyphVector.
+ */
+ public Shape getOutline()
+ {
+ GeneralPath path = new GeneralPath();
+ for( int i = 0; i < getNumGlyphs(); i++ )
+ path.append(getGlyphOutline(i), false);
+ return path;
+ }
+
+ /**
+ * TODO:
+ * FreeType does not currently have an API for the JSTF table. We should
+ * probably get the table ourselves from FT and pass it to some parser
+ * which the native font peers will need.
+ */
+ public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex)
+ {
+ return null;
+ }
+
+ /**
+ * Returns the outline of the entire vector, drawn at (x,y).
+ */
+ public Shape getOutline(float x, float y)
+ {
+ AffineTransform tx = AffineTransform.getTranslateInstance( x, y );
+ GeneralPath gp = (GeneralPath)getOutline();
+ gp.transform( tx );
+ return gp;
+ }
+
+ /**
+ * Returns the visual bounds of the entire GlyphVector.
+ * May be off by a pixel or two due to hinting/rasterization.
+ */
+ public Rectangle2D getVisualBounds()
+ {
+ return getOutline().getBounds2D();
+ }
+
+ /**
+ * Sets the position of a glyph.
+ */
+ public void setGlyphPosition(int glyphIndex, Point2D newPos)
+ {
+ glyphPositions[glyphIndex*2] = (float)(newPos.getX());
+ glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY());
+ logicalBounds = null;
+ }
+
+ /**
+ * Sets the transform of a single glyph.
+ */
+ public void setGlyphTransform(int glyphIndex, AffineTransform newTX)
+ {
+ // The identity transform should never be in the glyphTransforms array;
+ // using and checking for nulls can be much faster.
+ if (newTX != null && newTX.isIdentity())
+ newTX = null;
+
+ // If the old and new transforms are identical, bail
+ if (glyphTransforms[glyphIndex] == null && newTX == null)
+ return;
+
+ if (newTX != null && newTX.equals(glyphTransforms[glyphIndex]))
+ return;
+
+ // Invalidate bounds cache and set new transform
+ logicalBounds = null;
+ glyphTransforms[glyphIndex] = newTX;
+ }
+}