Imported GNU Classpath 0.90

Imported GNU Classpath 0.90
       * scripts/makemake.tcl: LocaleData.java moved to gnu/java/locale.

       * sources.am: Regenerated.
       * gcj/javaprims.h: Regenerated.
       * Makefile.in: Regenerated.
       * gcj/Makefile.in: Regenerated.
       * include/Makefile.in: Regenerated.
       * testsuite/Makefile.in: Regenerated.

       * gnu/java/lang/VMInstrumentationImpl.java: New override.
       * gnu/java/net/local/LocalSocketImpl.java: Likewise.
       * gnu/classpath/jdwp/VMMethod.java: Likewise.
       * gnu/classpath/jdwp/VMVirtualMachine.java: Update to latest
       interface.
       * java/lang/Thread.java: Add UncaughtExceptionHandler.
       * java/lang/reflect/Method.java: Implements GenericDeclaration and
       isSynthetic(),
       * java/lang/reflect/Field.java: Likewise.
       * java/lang/reflect/Constructor.java
       * java/lang/Class.java: Implements Type, GenericDeclaration,
       getSimpleName() and getEnclosing*() methods.
       * java/lang/Class.h: Add new public methods.
       * java/lang/Math.java: Add signum(), ulp() and log10().
       * java/lang/natMath.cc (log10): New function.
       * java/security/VMSecureRandom.java: New override.
       * java/util/logging/Logger.java: Updated to latest classpath
       version.
       * java/util/logging/LogManager.java: New override.

From-SVN: r113887
This commit is contained in:
Mark Wielaard
2006-05-18 17:29:21 +00:00
parent eaec4980e1
commit 4f9533c772
1640 changed files with 126485 additions and 104808 deletions
@@ -0,0 +1,313 @@
/* FontDelegate.java -- Interface implemented by all font delegates.
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.font;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.text.CharacterIterator;
import java.util.Locale;
/**
* The interface that all font delegate objects implement,
* irrespective of where they get their information from.
*
* <p><b>Thread Safety:</b> All classes that implement the
* <code>FontDelegate</code> interface must allow calling these
* methods from multiple concurrent threads. The delegates are
* responsible for performing the necessary synchronization.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public interface FontDelegate
{
/**
* Returns the full name of this font face in the specified
* locale, for example <i>&#x201c;Univers Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the face name.
*/
public String getFullName(Locale locale);
/**
* Returns the name of the family to which this font face belongs,
* for example <i>&#x201c;Univers&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the family name.
*/
public String getFamilyName(Locale locale);
/**
* Returns the name of this font face inside the family, for example
* <i>&#x201c;Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the name of the face inside its family.
*/
public String getSubFamilyName(Locale locale);
/**
* Returns the PostScript name of this font face, for example
* <i>&#x201c;Helvetica-Bold&#x201d;</i>.
*
* @return the PostScript name, or <code>null</code> if the font
* does not provide a PostScript name.
*/
public String getPostScriptName();
/**
* Returns the number of glyphs in this font face.
*/
public int getNumGlyphs();
/**
* Returns the index of the glyph which gets displayed if the font
* cannot map a Unicode code point to a glyph. Many fonts show this
* glyph as an empty box.
*/
public int getMissingGlyphCode();
/**
* Creates a GlyphVector by mapping each character in a
* CharacterIterator to the corresponding glyph.
*
* <p>The mapping takes only the font&#x2019;s <code>cmap</code>
* tables into consideration. No other operations (such as glyph
* re-ordering, composition, or ligature substitution) are
* performed. This means that the resulting GlyphVector will not be
* correct for text in languages that have complex
* character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or
* Thai.
*
* @param font the font object that the created GlyphVector
* will return when it gets asked for its font. This argument is
* needed because the public API works with java.awt.Font,
* not with some private delegate like OpenTypeFont.
*
* @param frc the font rendering parameters that are used for
* measuring glyphs. The exact placement of text slightly depends on
* device-specific characteristics, for instance the device
* resolution or anti-aliasing. For this reason, any measurements
* will only be accurate if the passed
* <code>FontRenderContext</code> correctly reflects the relevant
* parameters. Hence, <code>frc</code> should be obtained from the
* same <code>Graphics2D</code> that will be used for drawing, and
* any rendering hints should be set to the desired values before
* obtaining <code>frc</code>.
*
* @param ci a CharacterIterator for iterating over the
* characters to be displayed.
*/
public GlyphVector createGlyphVector(Font font,
FontRenderContext frc,
CharacterIterator ci);
/**
* Determines the advance width and height for a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is well
* possible that both values are non-zero, for example for rotated
* text or for Urdu fonts.
*/
public void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance);
/**
* Returns the shape of a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts, this
* parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional
* metrics, <code>false</code> for rounding the result to a pixel
* boundary.
*
* @return the scaled and grid-fitted outline of the specified
* glyph, or <code>null</code> for bitmap fonts.
*/
public GeneralPath getGlyphOutline(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics);
/**
* Returns a name for the specified glyph. This is useful for
* generating PostScript or PDF files that embed some glyphs of a
* font.
*
* <p><b>Names are not unique:</b> Under some rare circumstances,
* the same name can be returned for different glyphs. It is
* therefore recommended that printer drivers check whether the same
* name has already been returned for antoher glyph, and make the
* name unique by adding the string ".alt" followed by the glyph
* index.</p>
*
* <p>This situation would occur for an OpenType or TrueType font
* that has a <code>post</code> table of format 3 and provides a
* mapping from glyph IDs to Unicode sequences through a
* <code>Zapf</code> table. If the same sequence of Unicode
* codepoints leads to different glyphs (depending on contextual
* position, for example, or on typographic sophistication level),
* the same name would get synthesized for those glyphs.
*
* @param glyphIndex the glyph whose name the caller wants to
* retrieve.
*/
public String getGlyphName(int glyphIndex);
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public float getAscent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
}
@@ -0,0 +1,90 @@
/* FontFactory.java -- Factory for font delegates.
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.font;
import java.nio.ByteBuffer;
import java.awt.FontFormatException;
import gnu.java.awt.font.opentype.OpenTypeFontFactory;
/**
* A factory for creating font delegate objects.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public final class FontFactory
{
/**
* The constructor is private so nobody can construct an instance
*/
private FontFactory()
{
}
/**
* Creates FontDelegate objects for the fonts in the specified buffer.
* The following font formats are currently recognized:
* recognized font formats are:
*
* <p><ul>
* <li>OpenType (*.otf);</li>
* <li>TrueType (*.ttf);</li>
* <li>TrueType Collections (*.ttc);</li>
* <li>Apple MacOS X data-fork font (*.dfont).</li></ul>
*
* <p>Some formats may contain more than a single font, for example
* *.ttc and *.dfont files. This is the reason why this function
* returns an array.
*
* <p>The implementation reads data from the buffer only when
* needed. Therefore, it greatly increases efficiency if
* <code>buf</code> has been obtained through mapping a file into
* the virtual address space.
*
* @throws FontFormatException if the font data is not in one of the
* known formats.
*/
public static FontDelegate[] createFonts(ByteBuffer buf)
throws FontFormatException
{
return OpenTypeFontFactory.createFonts(buf);
}
}
@@ -0,0 +1,596 @@
/* GNUGlyphVector.java -- The GNU implementation of GlyphVector.
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.font;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphJustificationInfo;
import java.awt.font.GlyphVector;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
* The GNU implementation of the abstract GlyphVector class, which
* uses the services provided by a FontDelegate for its functionality.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public class GNUGlyphVector
extends GlyphVector
{
private FontDelegate fontDelegate;
private Font font;
private FontRenderContext renderContext;
private int[] glyphs;
private float fontSize;
private AffineTransform transform;
private boolean valid;
/**
* The position of each glyph. The horizontal position of the
* <code>i</code>-th glyph is at <code>pos[i * 2]</code>, its
* vertical position at <code>pos[i * 2 + 1]</code>. The total
* advance width of the entire vector is stored at
* <code>pos[numGlyphs]</code>, the total advance height at
* <code>pos[numGlyphs + 1]</code>.
*/
private float[] pos;
private AffineTransform[] transforms;
private int layoutFlags;
/**
* Constructs a new GNUGlyphVector.
*
* @param fontDelegate the FontDelegate that creates this vector.
*
* @param font the Font that this GlyphVector will return for {@link
* #getFont()}. That object is also used to determine the point
* size, which affects the affine transformation used by the font
* scaler.
*
* @param renderContext an object with parameters for font
* rendering, such as whether anti-aliasing is enabled.
*
* @param glyphs the glyphs in this vector.
*/
public GNUGlyphVector(FontDelegate fontDelegate,
Font font,
FontRenderContext renderContext,
int[] glyphs)
{
this.fontDelegate = fontDelegate;
this.font = font;
this.renderContext = renderContext;
this.glyphs = glyphs;
fontSize = font.getSize2D();
transform = font.getTransform(); // returns a modifiable copy
transform.concatenate(renderContext.getTransform());
}
/**
* Returns the font of the glyphs in this GlyphVector.
*/
public Font getFont()
{
return font;
}
/**
* Returns the FontRenderContext that is used to calculate the
* extent and position of the glyphs.
*/
public FontRenderContext getFontRenderContext()
{
return renderContext;
}
/**
* Moves each glyph in the vector to its default position.
*/
public void performDefaultLayout()
{
float x, y, advanceWidth, advanceHeight;
int i, p;
AffineTransform tx;
Point2D.Float advance = new Point2D.Float();
pos = new float[(glyphs.length + 1) * 2];
x = y = 0.0f;
p = 0;
for (i = p = 0; i < glyphs.length; i++)
{
p += 2;
if ((transforms == null) || (tx = transforms[i]) == null)
tx = this.transform;
else
{
tx = new AffineTransform(tx);
tx.concatenate(this.transform);
}
fontDelegate.getAdvance(glyphs[i], fontSize, tx,
renderContext.isAntiAliased(),
renderContext.usesFractionalMetrics(),
/* horizontal */ true,
advance);
pos[p] = x += advance.x;
pos[p + 1] = y += advance.y;
}
valid = true;
}
/**
* Determines the number of glyphs in this GlyphVector.
*/
public int getNumGlyphs()
{
return glyphs.length;
}
/**
* Determines the glyph number by index in this vector.
* Glyph numbers are specific to each font, so two fonts
* will likely assign different numbers to the same glyph.
*
* @param glyphIndex the index of the glyph whose glyph number is to
* be retrieved.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code>
* is not in the range <code[0 .. getNumGlyphs() - 1]</code>.
*/
public int getGlyphCode(int glyphIndex)
{
/* The exception is thrown automatically if the index is out
* of the valid bounds.
*/
return glyphs[glyphIndex];
}
/**
* Returns a slice of this GlyphVector.
*
* @param firstGlyphIndex the index of the first glyph in the
* returned slice.
*
* @param numEntries the size of the returned slice.
*
* @param outCodes a pre-allocated array for storing the slice,
* or <code>null</code> to cause allocation of a new array.
*
* @return a slice of this GlyphVector. If <code>outCodes</code>
* is <code>null</code>, the slice will be stored into a freshly
* allocated array; otherwise, the result will be stored into
* <code>outCodes</code>.
*/
public int[] getGlyphCodes(int firstGlyphIndex,
int numEntries,
int[] outCodes)
{
if (numEntries < 0)
throw new IllegalArgumentException();
if (outCodes == null)
outCodes = new int[numEntries];
System.arraycopy(glyphs, firstGlyphIndex, outCodes, 0, numEntries);
return outCodes;
}
public Rectangle2D getLogicalBounds()
{
float ascent, descent;
validate();
return new Rectangle2D.Float(0, 0,
pos[pos.length - 2],
getAscent() - getDescent());
}
public Rectangle2D getVisualBounds()
{
validate();
// FIXME: Not yet implemented.
return getLogicalBounds();
}
/**
* Returns the shape of this GlyphVector.
*/
public Shape getOutline()
{
validate();
return getOutline(0.0f, 0.0f);
}
/**
* Returns the shape of this GlyphVector, translated to the
* specified position.
*
* @param x the horizontal position for rendering this vector.
* @param y the vertical position for rendering this vector.
*/
public Shape getOutline(float x, float y)
{
validate();
GeneralPath outline = new GeneralPath();
int len = glyphs.length;
for (int i = 0; i < len; i++)
{
GeneralPath p = new GeneralPath(getGlyphOutline(i));
outline.append(p, false);
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
outline.transform(t);
return outline;
}
/**
* Determines the shape of the specified glyph.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
* not in the range <code[0 .. getNumGlyphs()]</code>.
*/
public Shape getGlyphOutline(int glyphIndex)
{
AffineTransform tx, glyphTx;
GeneralPath path;
validate();
if ((transforms != null)
&& ((glyphTx = transforms[glyphIndex]) != null))
{
tx = new AffineTransform(transform);
tx.concatenate(glyphTx);
}
else
tx = transform;
path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx,
renderContext.isAntiAliased(),
renderContext.usesFractionalMetrics());
tx = new AffineTransform();
tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]);
path.transform(tx);
return path;
}
/**
* Determines the position of the specified glyph, or the
* total advance width and height of the vector.
*
* @param glyphIndex the index of the glyph in question.
* If this value equals <code>getNumGlyphs()</code>, the
* position <i>after</i> the last glyph will be returned,
* which is the total advance width and height of the vector.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
* not in the range <code[0 .. getNumGlyphs()]</code>.
*/
public Point2D getGlyphPosition(int glyphIndex)
{
validate();
return new Point2D.Float(pos[glyphIndex * 2],
pos[glyphIndex * 2 + 1]);
}
/**
* Moves the specified glyph to a new position, or changes the
* advance width and height of the entire glyph vector.
*
* <p>Note that the position of an individual glyph may also
* affected by its affine transformation.
*
* @param glyphIndex the index of the moved glyph. If
* <code>glyphIndex</code> equals the total number of glyphs in this
* vector, the advance width and height of the vector is changed.
*
* @param position the new position of the glyph.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
* not in the range <code[0 .. getNumGlyphs()]</code>.
*/
public void setGlyphPosition(int glyphIndex, Point2D position)
{
validate();
pos[glyphIndex * 2] = (float) position.getX();
pos[glyphIndex * 2 + 1] = (float) position.getY();
}
/**
* Returns the affine transformation that is applied to the
* glyph at the specified index.
*
* @param glyphIndex the index of the glyph whose transformation
* is to be retrieved.
*
* @return an affine transformation, or <code>null</code>
* for the identity transformation.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
* not in the range <code[0 .. getNumGlyphs() - 1]</code>.
*/
public AffineTransform getGlyphTransform(int glyphIndex)
{
if (transforms == null)
return null;
else
return transforms[glyphIndex];
}
/**
* Applies an affine transformation to the glyph at the specified
* index.
*
* @param glyphIndex the index of the glyph to which the
* transformation is applied.
*
* @param transform the affine transformation for the glyph, or
* <code>null</code> for an identity transformation.
*/
public void setGlyphTransform(int glyphIndex,
AffineTransform transform)
{
if (transforms == null)
transforms = new AffineTransform[glyphs.length];
transforms[glyphIndex] = transform;
/* If the GlyphVector has only a transform for a single glyph, and
* the caller clears its transform, the FLAG_HAS_TRANSFORMS bit
* should be cleared in layoutFlags. However, this would require
* that we keep track of the number of transformed glyphs, or that
* we count them when a transform is cleared. This would
* complicate the code quite a bit. Note that the only drawback of
* wrongly setting FLAG_HAS_TRANSFORMS is that a slower code path
* might be taken for rendering the vector. Right now, we never
* really look at the flag, so it does not make any difference.
*/
if (transform != null)
layoutFlags |= FLAG_HAS_TRANSFORMS;
valid = false;
}
/**
* Returns flags that can be used for optimizing the rendering
* of this GlyphVector.
*
* @return a bit mask with the applicable flags set.
*
* @since 1.4
*
* @see GlyphVector#FLAG_HAS_POSITION_ADJUSTMENTS
* @see GlyphVector#FLAG_HAS_TRANSFORMS
* @see GlyphVector#FLAG_RUN_RTL
* @see GlyphVector#FLAG_COMPLEX_GLYPHS
* @see GlyphVector#FLAG_MASK
*/
public int getLayoutFlags()
{
return layoutFlags;
}
/**
* Returns the positions of a range of glyphs in this vector.
*
* @param firstGlyphIndex the index of the first glyph whose
* position is retrieved.
*
* @param numGlyphs the number of glyphs whose positions
* are retrieved.
*
* @param outPositions an array for storing the results
* (the length must be at least twice <code>numGlyphs</code>),
* or <code>null</code> for freshly allocating an array.
*
* @return an array with the glyph positions. The horizontal
* position of the <code>i</code>-th glyph is at index <code>2 *
* i</code>, the vertical position at index <code>2 * i + 1</code>.
*
* @throws IllegalArgumentException if <code>numGlyphs</code>
* is less than zero.
*
* @throws IndexOutOfBoundsException if either
* <code>firstGlyphIndex</code> or <code>(firstGlyphIndex +
* numGlyphs)</code> is not in the range <code>[0 .. getNumGlyphs() -
* 1]</code>.
*/
public float[] getGlyphPositions(int firstGlyphIndex,
int numGlyphs,
float[] outPositions)
{
if (numGlyphs < 0)
throw new IllegalArgumentException();
validate();
if (outPositions == null)
outPositions = new float[numGlyphs * 2];
System.arraycopy(/*src */ pos, /* srcStart */ firstGlyphIndex * 2,
/* dest */ outPositions, /* destStart */ 0,
/* length */ numGlyphs * 2);
return outPositions;
}
private float getAscent()
{
return fontDelegate.getAscent(fontSize, transform,
renderContext.isAntiAliased(),
renderContext.usesFractionalMetrics(),
/* horizontal */ true);
}
private float getDescent()
{
return fontDelegate.getDescent(fontSize, transform,
renderContext.isAntiAliased(),
renderContext.usesFractionalMetrics(),
/* horizontal */ true);
}
public Shape getGlyphLogicalBounds(int glyphIndex)
{
float x, y, ascent;
validate();
ascent = getAscent();
x = pos[glyphIndex * 2];
y = pos[glyphIndex * 2 + 1];
return new Rectangle2D.Float(x, y - ascent,
pos[(glyphIndex + 1) * 2] - x,
ascent - getDescent());
}
public Shape getGlyphVisualBounds(int glyphIndex)
{
return getGlyphOutline(glyphIndex).getBounds2D();
}
/**
* Determines the metrics of the glyph at the specified index.
*
* @param glyphIndex the index of the glyph whose metrics is to be
* retrieved.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
* not in the range <code[0 .. getNumGlyphs() - 1]</code>.
*/
public GlyphMetrics getGlyphMetrics(int glyphIndex)
{
// FIXME: Not yet implemented.
throw new UnsupportedOperationException();
}
/**
* Determines the justification information for the glyph at the
* specified index.
*
* @param glyphIndex the index of the glyph whose justification
* information is to be retrieved.
*
* @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
* not in the range <code[0 .. getNumGlyphs() - 1]</code>.
*/
public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex)
{
// FIXME: Not yet implemented.
throw new UnsupportedOperationException();
}
/**
* Determines whether another GlyphVector is for the same font and
* rendering context, uses the same glyphs and positions them to the
* same location.
*
* @param other the GlyphVector to compare with.
*
* @return <code>true</code> if the two vectors are equal,
* <code>false</code> otherwise.
*/
public boolean equals(GlyphVector other)
{
GNUGlyphVector o;
if (!(other instanceof GNUGlyphVector))
return false;
o = (GNUGlyphVector) other;
if ((this.font != o.font)
|| (this.fontDelegate != o.fontDelegate)
|| (this.renderContext != o.renderContext)
|| (this.glyphs.length != o.glyphs.length))
return false;
for (int i = 0; i < glyphs.length; i++)
if (this.glyphs[i] != o.glyphs[i])
return false;
validate();
o.validate();
for (int i = 0; i < pos.length; i++)
if (this.pos[i] != o.pos[i])
return false;
return true;
}
private void validate()
{
if (!valid)
performDefaultLayout();
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,235 @@
/* MacResourceFork.java -- Parses MacOS resource forks.
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.font.opentype;
import java.nio.ByteBuffer;
/**
* A class for accessing data that is stored in the resource fork of
* Macintosh files. Writing resource forks is currently not supported.
*
* <p>The gnu.java.awt.font package uses this class for accessing
* fonts in the MacOS X ".dfont" format, which is is a file in the
* format of a Macintosh resource fork, but stored in the normal data
* fork of the file.
*
* <p>The implementation has been designed to work efficiently with
* the virtual memory subsystem. It is recommended to pass an
* instance of {@link java.nio.MappedByteBuffer} to the constructor.
*
* <p>Thread Safety: All access is synchronized on the ByteBuffer
* that is passed to the constructor.
*
* @see <a href=
* "http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html"
* >Apple&#x2019; developer documentation about the Resource File
* Format</a>
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class MacResourceFork
{
int[] types;
Resource[][] resources;
ByteBuffer buf;
public MacResourceFork(ByteBuffer buf)
{
int typeListOffset;
int refListOffset;
int nameListOffset;
int mapOffset, mapLen;
int dataOffset, dataLen;
int numTypes;
synchronized (buf)
{
buf = buf.duplicate();
this.buf = buf;
buf.position(0);
dataOffset = buf.getInt();
mapOffset = buf.getInt();
dataLen = buf.getInt();
mapLen = buf.getInt();
buf.position(mapOffset + 24);
refListOffset = mapOffset + buf.getChar();
nameListOffset = mapOffset + buf.getChar();
numTypes = buf.getChar() + 1;
types = new int[numTypes];
resources = new Resource[numTypes][];
/* Parse resource type list. */
typeListOffset = buf.position();
for (int i = 0; i < numTypes; i++)
{
buf.position(typeListOffset + 8 * i);
int resType = buf.getInt();
int numRes = buf.getChar() + 1;
types[i] = resType;
resources[i] = new Resource[numRes];
buf.position(refListOffset + buf.getChar());
for (int j = 0; j < numRes; j++)
{
short resID = buf.getShort();
int resNameOffset = nameListOffset + buf.getChar();
int resDataOffset = buf.getInt();
byte resAttr = (byte) (resDataOffset >> 24);
resDataOffset = dataOffset + (resDataOffset & 0x00ffffff);
buf.getInt(); /* skip four reserved bytes */
Resource rsrc = new Resource(buf, resType, resID, resDataOffset,
resNameOffset);
resources[i][j] = rsrc;
}
}
}
}
public Resource[] getResources(int type)
{
synchronized (buf)
{
for (int i = 0; i < types.length; i++)
{
if (types[i] == type)
return resources[i];
}
}
return null;
}
public Resource getResource(int type, short id)
{
Resource[] res;
synchronized (buf)
{
for (int i = 0; i < types.length; i++)
{
if (types[i] != type)
continue;
res = resources[i];
for (int j = 0; j < res.length; j++)
if (res[j].getID() == id)
return res[j];
}
}
return null;
}
/**
* A single resource that is contained in a resource fork.
*/
public static final class Resource
{
int type;
short id;
byte attribute;
int nameOffset;
int dataOffset;
ByteBuffer buf;
private Resource(ByteBuffer buf,
int type, short id, int dataOffset, int nameOffset)
{
this.buf = buf;
this.type = type;
this.id = id;
this.dataOffset = dataOffset;
this.nameOffset = nameOffset;
}
/**
* Returns the type of this resource.
*
* @return an <code>int</code> encoding a four-byte type tag,
* such as <code>0x464f4e54</code> for <code>'FONT'</code>.
*/
public int getType()
{
return type;
}
/**
* Returns the ID of this resource.
*/
public short getID()
{
return id;
}
/**
* Retrieves the content of the resource. Only one page of memory
* is touched, irrespective of the actual size of the resource.
*/
public ByteBuffer getContent()
{
synchronized (buf)
{
buf.limit(buf.capacity());
int len = buf.getInt(dataOffset);
buf.position(dataOffset + 4).limit(dataOffset + 4 + len);
return buf.slice();
}
}
/**
* Determines the length of the resource in bytes.
*/
public int getLength()
{
synchronized (buf)
{
return buf.getInt(dataOffset);
}
}
}
}
@@ -0,0 +1,686 @@
/* NameDecoder.java -- Decodes names of OpenType and TrueType fonts.
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.font.opentype;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Locale;
/**
* A utility class that helps with decoding the names of OpenType
* and TrueType fonts.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
class NameDecoder
{
public static final int NAME_COPYRIGHT = 0;
/**
* Specifies the name of the family to which a font belongs, for
* example &#x201c;Univers&#x201d;.
*/
public static final int NAME_FAMILY = 1;
/**
* Specified the name of the font inside its family, for
* example &#x201c;Light&#x201d;.
*/
public static final int NAME_SUBFAMILY = 2;
public static final int NAME_UNIQUE = 3;
/**
* Specifies the full human-readable name of a font, for example
* &#x201c;Univers Light&#x201d;
*/
public static final int NAME_FULL = 4;
public static final int NAME_VERSION = 5;
/**
* Specifies the PostScript name of a font, for example
* &#x201c;Univers-Light&#x201d;.
*/
public static final int NAME_POSTSCRIPT = 6;
public static final int NAME_TRADEMARK = 7;
public static final int NAME_MANUFACTURER = 8;
public static final int NAME_DESIGNER = 9;
public static final int NAME_DESCRIPTION = 10;
public static final int NAME_VENDOR_URL = 11;
public static final int NAME_DESIGNER_URL = 12;
public static final int NAME_LICENSE = 13;
public static final int NAME_LICENSE_URL = 14;
public static final int NAME_PREFERRED_FAMILY = 16;
public static final int NAME_PREFERRED_SUBFAMILY = 17;
public static final int NAME_FULL_MACCOMPATIBLE = 18;
public static final int NAME_SAMPLE_TEXT = 19;
public static final int NAME_POSTSCRIPT_CID = 20;
private static final int PLATFORM_MACINTOSH = 1;
private static final int PLATFORM_MICROSOFT = 3;
public static String getName(ByteBuffer nameTable,
int name, Locale locale)
{
int numRecords;
int macLanguage, msLanguage;
int offset;
int namePlatform, nameEncoding, nameLanguage, nameID, nameLen;
int nameStart;
String result;
boolean match;
if (nameTable == null)
return null;
nameTable.position(0);
/* We understand only format 0 of the name table. */
if (nameTable.getChar() != 0)
return null;
macLanguage = getMacLanguageCode(locale);
msLanguage = getMicrosoftLanguageCode(locale);
numRecords = nameTable.getChar();
offset = nameTable.getChar();
for (int i = 0; i < numRecords; i++)
{
namePlatform = nameTable.getChar();
nameEncoding = nameTable.getChar();
nameLanguage = nameTable.getChar();
nameID = nameTable.getChar();
nameLen = nameTable.getChar();
nameStart = offset + nameTable.getChar();
if (nameID != name)
continue;
match = false;
switch (namePlatform)
{
case PLATFORM_MACINTOSH:
if ((nameLanguage == macLanguage) || (locale == null))
match = true;
else
{
switch (macLanguage)
{
case 49: /* Azerbaijani/Cyrillic */
match = (nameLanguage == /* Azerbaijani/Arabic */ 50)
|| (nameLanguage == /* Azerbaijani/Roman */ 150);
break;
case 57: /* Mongolian/Mongolian */
match = (nameLanguage == /* Mongolian/Cyrillic */ 58);
break;
case 83: /* Malay/Roman */
match = (nameLanguage == /* Malay/Arabic */ 84);
break;
}
}
break;
case PLATFORM_MICROSOFT:
if (((nameLanguage & 0xff) == msLanguage) || (locale == null))
match = true;
break;
}
if (match)
{
result = decodeName(namePlatform, nameEncoding, nameLanguage,
nameTable, nameStart, nameLen);
if (result != null)
return result;
}
}
return null;
}
/**
* The language codes used by the Macintosh operating system. MacOS
* defines numeric language identifiers in the range [0 .. 95] and
* [128 .. 150]. To map this numeric identifier into an ISO 639
* language code, multiply it by two and take the substring at that
* position.
*
* <p>ISO 639 has revised the code for some languages, namely
* <code>he</code> for Hebrew (formerly <code>iw</code>),
* <code>yi</code> (formerly <code>ji</code>), and <code>id</code>
* for Indonesian (formerly <code>in</code>). In those cases, this
* table intentionally contains the older, obsolete code. The
* reason is that this is the code which
* java.util.Locale.getLanguage() is specified to return. The
* implementation of {@link #getMacLanguageCode} depends on this.
*
* @see <a href=
* "http://www.unicode.org/unicode/onlinedat/languages.html"
* >Language Codes: ISO 639, Microsoft and Macintosh</a>
*/
private static final String macLanguageCodes
// 0 1 2
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
= "enfrdeitnlsvesdaptnoiwjaarfielismttrhrzhurhithkoltplhuetlv "
// 3 4 5
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "fofaruzhnlgdsqrocssksljisrmkbgukbeuzkkazazhykamokytgtkmnmnps"
// 6 7 8
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "kukssdbonesamrbnasgupaormlkntatesimykmloviintlmsmsamti sosw"
// 9 10 11
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "rwrn mgeo "
// 12 13 14
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ " cyeucalaqugnayttugtsjwsuglafbriugdgvgatoelkl"
// 15
// 0
+ "az";
/**
* The primary language IDs used by the Microsoft operating systems.
*
* <p>ISO 639 has revised the code for some languages, namely
* <code>he</code> for Hebrew (formerly <code>iw</code>),
* <code>yi</code> (formerly <code>ji</code>), and <code>id</code>
* for Indonesian (formerly <code>in</code>). In those cases, this
* table intentionally contains the older, obsolete code. The
* reason is that this is the code which
* java.util.Locale.getLanguage() is specified to return. The
* implementation of {@link #getMicrosoftLanguageCode} depends on
* this.
*
* @see <a href=
* "http://www.unicode.org/unicode/onlinedat/languages.html"
* >Language Codes: ISO 639, Microsoft and Macintosh</a>
*/
private static final String microsoftLanguageCodes
// 0 1 2
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
= " arbgcazhcsdadeelenesfifriwhuisitjakonlnoplptrmrorushsksqsv"
// 3 4 5
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "thtrurinukbesletlvlttgfavihyazeu mk ts xhzuafkafohimt "
// 6 7 8
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "gajimskkkyswtkuzttbnpaguortateknmlasmrsamnbocykmlomygl sd"
// 9 10 11
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ " si iuam ksnefypstl ha yo omtign laso";
/**
* Maps a Java Locale into a MacOS language code.
*
* <p>For languages that are written in several script systems,
* MacOS defines multiple language codes. Java Locales have a
* variant which could be used for that purpose, but a small
* test program revealed that with Sun's JDK 1.4.1_01, only two
* of 134 available Locales have a variant tag (namely no_NO_NY
* and th_TH_TH).</p>
*
* <p>The following cases are problematic:
*
* <ul> <li>Azerbaijani (az): The MacOS language code is 49 if
* Azerbaijani is written in the Cyrillic script; 50 if written in
* the Arabic script; 150 if written in the Roman script. This
* method will always return 49 for the Azerbaijani locale.</li>
*
* <li>Mongolian (mn): The MacOS language code is 57 if Mongolian is
* written in the Mongolian script; 58 if written in the Cyrillic
* script. This method will always return 57 for the Mongolian
* locale.</li>
*
* <li>Malay (ms): The MacOS language code is 83 if Malay is written
* in the Roman script; 84 if written in the Arabic script. This
* method will always return 83 for the Malay locale.</li> </ul>
*
* @return a MacOS language code, or -1 if there is no such code for
* <code>loc</code>&#x2019;s language.
*/
private static int getMacLanguageCode(Locale loc)
{
int code;
if (loc == null)
return -1;
code = findLanguageCode(loc.getLanguage(), macLanguageCodes);
switch (code)
{
case 19:
/* Traditional Chinese (MacOS language #19) and and Simplified
* Chinese (MacOS language #33) both have "zh" as their ISO 639
* code.
*/
if (loc.equals(Locale.SIMPLIFIED_CHINESE))
code = 33;
break;
// Other special cases would be 49, 57 and 83, but we do not
// know what do do about them. See the method documentation for
// details.
}
return code;
}
/**
* Maps a Java Locale into a Microsoft language code.
*/
private static int getMicrosoftLanguageCode(Locale locale)
{
String isoCode;
int code;
if (locale == null)
return -1;
isoCode = locale.getLanguage();
code = findLanguageCode(isoCode, microsoftLanguageCodes);
if (code == -1)
{
if (isoCode.equals("hr") || isoCode.equals("sr"))
{
/* Microsoft uses code 26 for "sh" (Serbo-Croatian),
* "hr" (Croatian) and "sr" (Serbian). Our table contains
* "sh".
*/
code = 26;
}
else if (isoCode.equals("gd"))
{
/* Microsoft uses code 60 for "gd" (Scottish Gaelic) and
* "ga" (Irish Gaelic). Out table contains "ga".
*/
code = 60;
}
}
return code;
}
private static int findLanguageCode(String lang, String langCodes)
{
int index;
if (lang == null)
return -1;
if (lang.length() != 2)
return -1;
index = 0;
do
{
index = langCodes.indexOf(lang, index);
/* The index must be even to be considered a match. Otherwise, we
* could match with the second letter of one language and the
* first of antoher one.
*/
}
while (!((index < 0) || ((index & 1) == 0)));
if (index < 0)
return -1;
index = index / 2;
return index;
}
private static String decodeName(int platform, int encoding, int language,
ByteBuffer buffer, int offset, int len)
{
byte[] byteBuf;
String charsetName;
int oldPosition;
charsetName = getCharsetName(platform, language, encoding);
if (charsetName == null)
return null;
byteBuf = new byte[len];
oldPosition = buffer.position();
try
{
buffer.position(offset);
buffer.get(byteBuf);
try
{
return new String(byteBuf, charsetName);
}
catch (UnsupportedEncodingException uex)
{
}
}
finally
{
buffer.position(oldPosition);
}
return null;
}
/**
* Maps a MacOS language code into a Java Locale.
*
* @param macLanguageCode the MacOS language code for
* the language whose Java locale is to be retrieved.
*
* @return an suitable Locale, or <code>null</code> if
* the mapping cannot be performed.
*/
private static Locale getMacLocale(int macLanguageCode)
{
String isoCode;
switch (macLanguageCode)
{
case 0: return Locale.ENGLISH;
case 1: return Locale.FRENCH;
case 2: return Locale.GERMAN;
case 3: return Locale.ITALIAN;
case 11: return Locale.JAPANESE;
case 23: return Locale.KOREAN;
case 19: return Locale.TRADITIONAL_CHINESE;
case 33: return Locale.SIMPLIFIED_CHINESE;
}
if ((macLanguageCode < 0) || (macLanguageCode > 150))
return null;
isoCode = macLanguageCodes.substring(macLanguageCode << 1,
(macLanguageCode + 1) << 1);
if (isoCode.charAt(0) == ' ')
return null;
return new Locale(isoCode);
}
/**
* Maps a Windows LCID into a Java Locale.
*
* @param lcid the Windows language ID whose Java locale
* is to be retrieved.
*
* @return an suitable Locale, or <code>null</code> if
* the mapping cannot be performed.
*/
private static Locale getWindowsLocale(int lcid)
{
/* FIXME: This is grossly incomplete. */
switch (lcid)
{
case 0x0407: return Locale.GERMAN;
case 0x0408: return new Locale("el", "GR");
case 0x0409: return Locale.ENGLISH;
case 0x040b: return new Locale("fi");
case 0x040c: return Locale.FRENCH;
case 0x0416: return new Locale("pt");
case 0x0807: return new Locale("de", "CH");
case 0x0809: return new Locale("en", "UK");
case 0x080c: return new Locale("fr", "BE");
case 0x0816: return new Locale("pt", "BR");
case 0x0c07: return new Locale("de", "AT");
case 0x0c09: return new Locale("en", "AU");
case 0x0c0c: return new Locale("fr", "CA");
case 0x1007: return new Locale("de", "LU");
case 0x1009: return new Locale("en", "CA");
case 0x100c: return new Locale("fr", "CH");
case 0x1407: return new Locale("de", "LI");
case 0x1409: return new Locale("en", "NZ");
case 0x140c: return new Locale("fr", "LU");
case 0x1809: return new Locale("en", "IE");
default:
return null;
}
}
/**
* Maps a Macintosh Script Manager code to the name of the
* corresponding Java Charset.
*
* @param macScript a MacOS ScriptCode, for example
* 6 for <code>smGreek</code>.
*
* @return a String that can be used to retrieve a Java
* CharsetDecorder, for example <code>MacGreek</code>, or
* <code>null</code> if <code>macScript</code> has an
* unsupported value.
*/
private static String getMacCharsetName(int macScript)
{
switch (macScript)
{
case 0: return "MacRoman";
case 1: return "MacJapanese";
case 2: return "MacKorean";
case 3: return "MacTradChinese";
case 4: return "MacArabic";
case 5: return "MacHebrew";
case 6: return "MacGreek";
case 7: return "MacCyrillic";
case 8: return "MacRSymbol";
case 9: return "MacDevanagari";
case 10: return "MacGurmukhi";
case 11: return "MacGujarati";
case 12: return "MacOriya";
case 13: return "MacBengali";
case 14: return "MacTamil";
case 15: return "MacTelugu";
case 16: return "MacKannada";
case 17: return "MacMalayalam";
case 18: return "MacSinhalese";
case 19: return "MacBurmese";
case 20: return "MacKhmer";
case 21: return "MacThai";
case 22: return "MacLao";
case 23: return "MacGeorgian";
case 24: return "MacArmenian";
case 25: return "MacSimpChinese";
case 26: return "MacTibetan";
case 27: return "MacMongolian";
case 28: return "MacEthiopic";
case 29: return "MacCentralEurope";
case 30: return "MacVietnamese";
case 31: return "MacExtArabic";
default: return null;
}
}
/**
* Maps a Microsoft locale ID (LCID) to the name of the
* corresponding Java Charset.
*
* @param lcid the Microsoft locale ID.
*
* @return a String that can be used to retrieve a Java
* CharsetDecorder, for example <code>windows-1252</code>, or
* <code>null</code> if <code>lcid</code> has an unsupported value.
*/
private static String getMicrosoftCharsetName(int lcid)
{
int lang;
char codePage = '?';
/* Extract the language code from the LCID. */
lang = lcid & 0x3ff;
/* In the majority of cases, the language alone determines the
* codepage.
*/
if (lang < 100)
codePage = (" 612D022322225022EC2202201?002A462110777 68 ?2 1 "
+ " 2 2 2112 ?1 1 2 2 ")
.charAt(lang);
/* There are a few exceptions, however, where multiple code pages
* are used for the same language. */
if (codePage == '?')
{
switch (lcid)
{
case 0x041a: // Croatian --> Windows-1250 (Central Europe)
case 0x081a: // Serbian (Latin) --> Windows-1250 (Central Europe)
codePage = '0';
break;
case 0x42c: // Azeri (Latin) --> Windows-1254 (Turkish)
case 0x443: // Uzbek (Latin) --> Windows-1254 (Turkish)
codePage = '4';
break;
case 0x82c: // Azeri (Cyrillic) --> Windows-1251 (Cyrillic)
case 0x843: // Uzbek (Cyrillic) --> Windows-1251 (Cyrillic)
case 0xc1a: // Serbian (Cyrillic) --> Windows-1251 (Cyrillic)
codePage = '1';
break;
}
}
switch (codePage)
{
case '0': return "windows-1250"; // Central Europe
case '1': return "windows-1251"; // Cyrillic
case '2': return "windows-1252"; // Latin 1
case '3': return "windows-1253"; // Greek
case '4': return "windows-1254"; // Turkish
case '5': return "windows-1255"; // Hebrew
case '6': return "windows-1256"; // Arabic
case '7': return "windows-1257"; // Baltic
case '8': return "windows-1258"; // Vietnam
case 'A': return "windows-874"; // Thai
case 'B': return "windows-936"; // Simplified Chinese, GBK
case 'C': return "windows-949"; // Korean
case 'D': return "windows-950"; // Traditional Chinese, Big5
case 'E': return "windows-932"; // Japanese Shift-JIS
default: return null;
}
}
/**
* Returns the Locale of an OpenType name.
*
* @param platform the OpenType platform ID.
*
* @param language the language tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS language code.
*
* @param encoding the encoding tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS script code.
*/
public static Locale getLocale(int platform, int language, int encoding)
{
switch (platform)
{
case 1: /* Apple Macintosh */
return getMacLocale(language);
case 3: /* Microsoft Windows */
return getWindowsLocale(language);
default:
return null;
}
}
/**
* Determines the name of the charset for an OpenType font name.
*
* @param platform the OpenType platform ID.
*
* @param language the language tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS language code.
*
* @param encoding the encoding tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS script code.
*
* @return a charset name such as <code>&quot;MacRoman&quot;</code>,
* or <code>null</code> if the combination is not known.
*/
public static String getCharsetName(int platform, int language, int encoding)
{
switch (platform)
{
case 1: /* Apple Macintosh */
return getMacCharsetName(encoding);
case 3: /* Microsoft Windows */
return getMicrosoftCharsetName(language);
default:
return null;
}
}
}
@@ -0,0 +1,825 @@
/* OpenTypeFont.java -- Manages OpenType and TrueType fonts.
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.font.opentype;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.OpenType;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;
import java.text.CharacterIterator;
import java.util.Locale;
import gnu.java.awt.font.FontDelegate;
import gnu.java.awt.font.GNUGlyphVector;
import gnu.java.awt.font.opentype.truetype.TrueTypeScaler;
/**
* A font that takes its data from OpenType or TrueType font tables.
*
* <p>OpenType is an extension of the TrueType font format. In addition
* to tables for names, kerning or layout, it also stores the shapes
* of individual glyphs. Three formats are recognized for glyphs:
* Quadratic splines (classic TrueType), cubic splines (PostScript),
* and bitmaps.
*
* @see <a
* href="http://partners.adobe.com/asn/tech/type/opentype/">Adobe&#x2019;s
* OpenType specification</a>
*
* @see <a
* href="http://developer.apple.com/fonts/TTRefMan/">Apple&#x2019;s</code>
* TrueType specification</a>
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public final class OpenTypeFont
implements FontDelegate
{
static final int TAG_OTTO = 0x4f54544f; // 'OTTO'
static final int TAG_SFNT = 0x73666e74; // 'sfnt'
static final int TAG_TRUE = 0x74727565; // 'true'
static final int TAG_TTCF = 0x74746366; // 'ttcf'
static final int TAG_ZAPF = 0x5a617066; // 'Zapf'
/**
* A buffer containing the font data. Note that this may well be an
* instance of the subclass MappedByteBuffer, in which case the
* virtual memory subsystem can more efficiently handle requests for
* font data. This is especially recommended for large font files
* that contain many glyphs that are rarely accessed.
*/
ByteBuffer buf;
/**
* The number of glyphs in this font.
*/
final int numGlyphs;
int[] tableTag, tableStart, tableLength;
/**
* The version of the font in 16.16 fixed-point encoding, for
* example 0x00010000 for version 1.0. There are also two special
* version IDs used by fonts for Apple Macintosh, namely 'true'
* (0x74727565) and 'typ1'. OpenType fonts sometimes have 'OTTO' as
* their version.
*/
private int version;
/**
* The number of font units per em. For fonts with TrueType
* outlines, this is usually a power of two (such as 2048). For
* OpenType fonts with PostScript outlines, other values are
* acceptable (such as 1000).
*/
private int unitsPerEm;
/**
* A factor to convert font units into ems. This value is <code>1 /
* unitsPerEm</code>.
*/
private float emsPerUnit;
/**
* The scaler to which the actual scaling work is delegated.
*/
private Scaler scaler;
/**
* A delegate object for mapping Unicode UCS-4 codepoints to glyph
* IDs.
*/
private CharGlyphMap cmap;
/**
* A delegate object for providing a name for each glyph.
*/
private GlyphNamer glyphNamer;
/**
* Constructs an OpenType or TrueType font.
*
* @param buf a buffer with the contents of the font file. It is
* recommended to use a <code>MappedByteBuffer</code> for very
* large font files.
*
* @param offsetTablePosition the position of the OpenType offset
* table in the font file. The offset table of most OpenType and
* TrueType fonts starts at position 0. However, so-called TrueType
* Collections support multiple OpenType fonts in a single file,
* which allows sharing some glyphs between fonts. If many glyphs
* are shared (for example all the Kanji glyphs between multiple
* Japanese fonts), the space savings can be considerable. In that
* case, the offset table of each individual font would start at its
* own position.
*
* @throws java.awt.FontFormatException if the font data is
* not in OpenType or TrueType format.
*/
OpenTypeFont(ByteBuffer buf, int offsetTablePosition)
throws FontFormatException
{
int numTables, searchRange, entrySelector, rangeShift;
//buf = buf.duplicate();
this.buf = buf;
buf.limit(buf.capacity());
buf.position(offsetTablePosition);
/* Check that the font data is in a supported format. */
version = buf.getInt();
switch (version)
{
case 0x00010000: // Microsoft TrueType
case OpenType.TAG_TYP1: // Adobe PostScript embeded in Apple SFNT ('typ1')
case TAG_SFNT: // Apple TrueType
case TAG_TRUE: // Apple TrueType
case TAG_OTTO: // OpenType
break;
default:
throw new FontFormatException("not in OpenType or TrueType format");
}
numTables = buf.getShort();
searchRange = buf.getShort();
entrySelector = buf.getShort();
rangeShift = buf.getShort();
tableTag = new int[numTables];
tableStart = new int[numTables];
tableLength = new int[numTables];
int lastTag = 0;
for (int i = 0; i < numTables; i++)
{
tableTag[i] = buf.getInt();
if (lastTag >= tableTag[i])
throw new FontFormatException("unordered OpenType table");
buf.getInt(); // ignore checksum
tableStart[i] = buf.getInt();
tableLength[i] = buf.getInt();
//System.out.println(tagToString(tableTag[i]) + ", " + tableLength[i]);
}
ByteBuffer head = getFontTable(OpenType.TAG_HEAD);
if ((head.getInt(0) != 0x00010000)
|| (head.getInt(12) != 0x5f0f3cf5))
throw new FontFormatException("unsupported head version");
unitsPerEm = head.getChar(18);
emsPerUnit = 1.0f / (float) unitsPerEm;
ByteBuffer maxp = getFontTable(OpenType.TAG_MAXP);
int maxpVersion = maxp.getInt(0);
switch (maxpVersion)
{
case 0x00005000: /* version 0.5, with wrong fractional part */
numGlyphs = maxp.getChar(4);
break;
case 0x00010000: /* version 1.0 */
numGlyphs = maxp.getChar(4);
scaler = new TrueTypeScaler(unitsPerEm,
getFontTable(OpenType.TAG_HHEA),
getFontTable(OpenType.TAG_HMTX),
getFontTable(OpenType.TAG_VHEA),
getFontTable(OpenType.TAG_VMTX),
maxp,
getFontTable(OpenType.TAG_CVT),
getFontTable(OpenType.TAG_FPGM),
/* loca format */ head.getShort(50),
getFontTable(OpenType.TAG_LOCA),
getFontTable(OpenType.TAG_GLYF),
getFontTable(OpenType.TAG_PREP));
break;
default:
throw new FontFormatException("unsupported maxp version");
}
}
/**
* Determines the index of a table into the offset table. The
* result can be used to find the offset and length of a table, as
* in <code>tableStart[getTableIndex(TAG_NAME)]</code>.
*
* @param tag the table identifier, for instance
* <code>OpenType.TAG_NAME</code>.
*
* @return the index of that table into the offset table, or
* -1 if the font does not contain the table specified by
* <code>tag</code>.
*/
private int getTableIndex(int tag)
{
/* FIXME: Since the font specification requires tableTag[] to be
* ordered, one should do binary search here.
*/
for (int i = 0; i < tableTag.length; i++)
if (tableTag[i] == tag)
return i;
return -1;
}
/**
* Returns the name of the family to which this font face belongs,
* for example <i>&#x201c;Univers&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the family name.
*/
public synchronized String getFamilyName(Locale locale)
{
String name;
if (locale == null)
locale = Locale.getDefault();
name = getName(NameDecoder.NAME_FAMILY, locale);
if (name == null)
name = getName(NameDecoder.NAME_FAMILY, Locale.ENGLISH);
if (name == null)
name = getName(NameDecoder.NAME_FAMILY, /* any language */ null);
if (name == null)
name = getName(NameDecoder.NAME_FULL, locale);
if (name == null)
name = getName(NameDecoder.NAME_FULL, /* any language */ null);
return name;
}
/**
* Returns the name of this font face inside the family, for example
* <i>&#x201c;Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the name of the face inside its family.
*/
public synchronized String getSubFamilyName(Locale locale)
{
String name;
if (locale == null)
locale = Locale.getDefault();
name = getName(NameDecoder.NAME_SUBFAMILY, locale);
if (name == null)
{
name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH);
if ("Regular".equals(name))
name = null;
}
if (name == null)
{
String lang = locale.getLanguage();
if ("de".equals(lang))
name = "Standard";
else if ("fr".equals(lang))
name = "Standard";
else if ("it".equals(lang))
name = "Normale";
else if ("nl".equals(lang))
name = "Normaal";
else if ("fi".equals(lang))
name = "Normaali";
else if ("sv".equals(lang))
name = "Normal";
else
name = "Regular";
}
return name;
}
/**
* Returns the full name of this font face, for example
* <i>&#x201c;Univers Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the face name.
*/
public synchronized String getFullName(Locale locale)
{
String name;
if (locale == null)
locale = Locale.getDefault();
name = getName(NameDecoder.NAME_FULL, locale);
if (name == null)
name = getName(NameDecoder.NAME_FULL, Locale.ENGLISH);
if (name == null)
name = getName(NameDecoder.NAME_FULL, /* any language */ null);
return name;
}
/**
* Returns the PostScript name of this font face, for example
* <i>&#x201c;Univers-Light&#x201d;</i>.
*
* @return the PostScript name, or <code>null</code> if the font
* does not provide a PostScript name.
*/
public synchronized String getPostScriptName()
{
return getName(NameDecoder.NAME_POSTSCRIPT, /* any language */ null);
}
/**
* Returns the number of glyphs in this font face.
*/
public int getNumGlyphs()
{
/* No synchronization is needed because the number of glyphs is
* set in the constructor, and it cannot change during the
* lifetime of the object.
*/
return numGlyphs;
}
/**
* Returns the index of the glyph which gets displayed if the font
* cannot map a Unicode code point to a glyph. Many fonts show this
* glyph as an empty box.
*/
public int getMissingGlyphCode()
{
/* No synchronization is needed because the result is constant. */
return 0;
}
/**
* The font&#x2019;s name table, or <code>null</code> if this
* table has not yet been accessed.
*/
private ByteBuffer nameTable;
/**
* Extracts a String from the font&#x2019;s name table.
*
* @param name the numeric TrueType or OpenType name ID.
*
* @param locale the locale for which names shall be localized, or
* <code>null</code> if the locale does mot matter because the name
* is known to be language-independent (for example, because it is
* the PostScript name).
*/
private String getName(int name, Locale locale)
{
if (nameTable == null)
nameTable = getFontTable(OpenType.TAG_NAME);
return NameDecoder.getName(nameTable, name, locale);
}
/**
* Returns the version of the font.
*
* @see java.awt.font.OpenType#getVersion
*
* @return the version in 16.16 fixed-point encoding, for example
* 0x00010000 for version 1.0.
*/
public int getVersion()
{
/* No synchronization is needed because the version is set in the
* constructor, and it cannot change during the lifetime of the
* object.
*/
return version;
}
/**
* Creates a view buffer for an OpenType table. The caller can
* access the returned buffer without needing to synchronize access
* from multiple threads.
*
* @param tag the table identifier, for example
* <code>OpenType.GLYF</code>.
*
* @return a slice of the underlying buffer containing the table, or
* <code>null</code> if the font does not contain the requested
* table.
*/
public synchronized ByteBuffer getFontTable(int tag)
{
int index, start, len;
ByteBuffer result;
index = getTableIndex(tag);
if (index < 0)
return null;
start = tableStart[index];
len = tableLength[index];
buf.limit(start + len).position(start);
result = buf.slice();
result.limit(len);
return result;
}
/**
* Returns the size of one of the tables in the font,
* or -1 if the table does not exist.
*/
public int getFontTableSize(int tag)
{
int index = getTableIndex(tag);
if (index == -1)
return index;
return tableLength[index];
}
private CharGlyphMap getCharGlyphMap()
{
if (cmap != null)
return cmap;
synchronized (this)
{
if (cmap == null)
{
int index = getTableIndex(OpenType.TAG_CMAP);
int start = tableStart[index];
buf.limit(start + tableLength[index]).position(start);
cmap = CharGlyphMap.forTable(buf);
}
return cmap;
}
}
/**
* Looks up a glyph in the font&#x2019;s <code>cmap</code> tables,
* without performing any glyph substitution or reordering. Because
* of this limitation, this method cannot be used for script systems
* that need advanced glyph mapping, such as Arabic, Korean, or even
* Latin with exotic accents.
*
* <p>It is safe to call this method from any thread.
*
* @param ucs4 the Unicode codepoint in the 32-bit Unicode character
* set UCS-4. Because UTF-16 surrogates do not correspond to a single
* glyph, it does not make sense to pass them here.
*
* @return the glyph index, or zero if the font does not contain
* a glyph for the specified codepoint.
*/
public int getGlyph(int ucs4)
{
return getCharGlyphMap().getGlyph(ucs4);
}
/**
* Creates a GlyphVector by mapping each character in a
* CharacterIterator to the corresponding glyph.
*
* <p>The mapping takes only the font&#x2019;s <code>cmap</code>
* tables into consideration. No other operations (such as glyph
* re-ordering, composition, or ligature substitution) are
* performed. This means that the resulting GlyphVector will not be
* correct for text in languages that have complex
* character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or
* Thai.
*
* @param font the font object that the created GlyphVector
* will return when it gets asked for its font. This argument is
* needed because the public API works with java.awt.Font,
* not with some private delegate like OpenTypeFont.
*
* @param frc the font rendering parameters that are used for
* measuring glyphs. The exact placement of text slightly depends on
* device-specific characteristics, for instance the device
* resolution or anti-aliasing. For this reason, any measurements
* will only be accurate if the passed
* <code>FontRenderContext</code> correctly reflects the relevant
* parameters. Hence, <code>frc</code> should be obtained from the
* same <code>Graphics2D</code> that will be used for drawing, and
* any rendering hints should be set to the desired values before
* obtaining <code>frc</code>.
*
* @param ci a CharacterIterator for iterating over the
* characters to be displayed.
*/
public synchronized GlyphVector createGlyphVector(Font font,
FontRenderContext frc,
CharacterIterator ci)
{
CharGlyphMap cmap;
int numGlyphs;
int[] glyphs;
int glyph;
int c;
cmap = getCharGlyphMap();
numGlyphs = ci.getEndIndex() - ci.getBeginIndex();
glyphs = new int[numGlyphs];
glyph = 0;
for (c = ci.first(); c != CharacterIterator.DONE; c = ci.next())
{
/* handle surrogate pairs */
if (c >> 10 == 0x36) // U+D800 .. U+DBFF: High surrogate
c = (((c & 0x3ff) << 10) | (ci.next() & 0x3ff)) + 0x10000;
glyphs[glyph] = cmap.getGlyph(c);
glyph += 1;
}
/* If we had surrogates, the allocated array is too large.
* Because this will occur very rarely, it seems acceptable to
* re-allocate a shorter array and copy the contents around.
*/
if (glyph != numGlyphs)
{
int[] newGlyphs = new int[glyph];
System.arraycopy(glyphs, 0, newGlyphs, 0, glyph);
glyphs = newGlyphs;
}
return new GNUGlyphVector(this, font, frc, glyphs);
}
/**
* Determines the advance width for a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is possible
* that both values are non-zero, for example if
* <code>transform</code> is a rotation, or in the case of Urdu
* fonts.
*/
public synchronized void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance)
{
/* Delegate the measurement to the scaler. The synchronization is
* needed because the scaler is not synchronized.
*/
scaler.getAdvance(glyphIndex, pointSize, transform,
antialias, fractionalMetrics, horizontal,
advance);
}
/**
* Returns the shape of a glyph.
*
* @param glyph the glyph whose advance width is to be determined
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts, this
* parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional
* metrics, <code>false</code> for rounding the result to a pixel
* boundary.
*
* @return the scaled and grid-fitted outline of the specified
* glyph, or <code>null</code> for bitmap fonts.
*/
public synchronized GeneralPath getGlyphOutline(int glyph,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics)
{
/* The synchronization is needed because the scaler is not
* synchronized.
*/
return scaler.getOutline(glyph, pointSize, transform,
antialias, fractionalMetrics);
}
/**
* Returns a name for the specified glyph. This is useful for
* generating PostScript or PDF files that embed some glyphs of a
* font.
*
* <p><b>Names are not unique:</b> Under some rare circumstances,
* the same name can be returned for different glyphs. It is
* therefore recommended that printer drivers check whether the same
* name has already been returned for antoher glyph, and make the
* name unique by adding the string ".alt" followed by the glyph
* index.</p>
*
* <p>This situation would occur for an OpenType or TrueType font
* that has a <code>post</code> table of format 3 and provides a
* mapping from glyph IDs to Unicode sequences through a
* <code>Zapf</code> table. If the same sequence of Unicode
* codepoints leads to different glyphs (depending on contextual
* position, for example, or on typographic sophistication level),
* the same name would get synthesized for those glyphs.
*
* @param glyphIndex the glyph whose name the caller wants to
* retrieve.
*/
public synchronized String getGlyphName(int glyphIndex)
{
if (glyphNamer == null)
glyphNamer = GlyphNamer.forTables(numGlyphs,
getFontTable(OpenType.TAG_POST),
getFontTable(TAG_ZAPF));
return glyphNamer.getGlyphName(glyphIndex);
}
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public synchronized float getAscent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal)
{
return scaler.getAscent(pointSize, transform,
antialiased, fractionalMetrics,
horizontal);
}
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public synchronized float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal)
{
return scaler.getDescent(pointSize, transform,
antialiased, fractionalMetrics,
horizontal);
}
/**
* Converts a four-byte tag identifier into a String that can be
* displayed when debugging this class.
*
* @param tag the tag as an <code>int</code>.
*
* @return the tag in human-readable form, for example
* <code>name</code> or <code>glyf</code>.
*/
static String tagToString(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 new String(c);
}
}
@@ -0,0 +1,140 @@
/* OpenTypeFontFactory.java -- Creates OpenType and TrueType fonts.
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.font.opentype;
import gnu.java.awt.font.FontDelegate;
import java.awt.FontFormatException;
import java.awt.font.OpenType;
import java.nio.ByteBuffer;
/**
* A factory for creating fonts that are stored in an
* <i>sfnt</i>-housed format, for example OpenType or TrueType.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public final class OpenTypeFontFactory
{
/**
* The constructor is private so nobody can construct an instance
* of this class.
*/
private OpenTypeFontFactory()
{
}
/**
* Creates FontDelegate objects for the fonts in the specified
* buffer. The following font formats are currently recognized:
*
* <p><ul>
* <li>OpenType (*.otf);</li>
* <li>TrueType (*.ttf);</li>
* <li>TrueType Collections (*.ttc);</li>
* <li>Apple MacOS X data-fork font (*.dfont).</li></ul>
*
* <p>Some formats may contain more than a single font, for example
* *.ttc and *.dfont files. This is the reason why this function
* returns an array.
*
* <p>The implementation reads data from the buffer only when
* needed. Therefore, it greatly increases efficiency if
* <code>buf</code> has been obtained through mapping a file into
* the virtual address space.
*
* @throws FontFormatException if the font data is not in one of the
* known formats.
*/
public static FontDelegate[] createFonts(ByteBuffer buf)
throws FontFormatException
{
OpenTypeFont[] fonts;
int version;
version = buf.getInt(0);
switch (version)
{
case 0x00010000: // Microsoft Windows TrueType
case OpenType.TAG_TYP1: // Apple MacOS PostScript ('typ1')
case OpenTypeFont.TAG_SFNT: // Apple MacOS TrueType ('sfnt')
case OpenTypeFont.TAG_TRUE: // Apple MacOS TrueType ('true')
case OpenTypeFont.TAG_OTTO: // OpenType
return new OpenTypeFont[] { new OpenTypeFont(buf, 0) };
}
/* TrueType Collection, see "TrueType Collections" in
* http://partners.adobe.com/asn/tech/type/opentype/otff.html
*/
if (version == OpenTypeFont.TAG_TTCF)
{
// This code has never been tested.
fonts = new OpenTypeFont[buf.getInt(8)];
for (int i = 0; i < fonts.length; i++)
fonts[i] = new OpenTypeFont(buf, buf.getInt(16 + 4 * i));
return fonts;
}
/* The MacOS X .dfont format is a Macintosh resource fork in
* a normal file, contaning one or several 'sfnt' resources.
* Unfortunately, MacOS resource forks have no magic code
* that could be used for identification. Instead, we just try
* to extract at least one 'sfnt'.
*/
try
{
MacResourceFork fork = new MacResourceFork(buf);
MacResourceFork.Resource[] rsrc;
rsrc = fork.getResources(OpenTypeFont.TAG_SFNT);
fonts = new OpenTypeFont[rsrc.length];
for (int i = 0; i < fonts.length; i++)
fonts[i] = new OpenTypeFont(rsrc[i].getContent(), 0);
return fonts;
}
catch (Exception ex)
{
}
throw new FontFormatException("not in OpenType or TrueType format");
}
}
@@ -0,0 +1,192 @@
/* Scaler.java -- Common superclass for font scalers.
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.font.opentype;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
/**
* An common superclass for all font scalers. The main task of font
* scaler is to retrieve a scaled and hinted outline for a glyph.
*
* <p>To make text more legible, high-quality fonts contain
* instructions (sometimes also called &#x201c;hints&#x201d;) for
* moving the scaled control points towards the coordinate grid of the
* display device.
*
* <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
* <i>not</i> safe to access from multiple concurrent
* threads. Synchronization needs to be performed externally. Usually,
* the font that uses this scaler already has obtained a lock before
* calling the scaler.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public abstract class Scaler
{
/**
* Retrieves the scaled outline of a glyph, adjusting control points
* to the raster grid if necessary.
*
* @param glyph the glyph number whose outline is retrieved.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias whether or not the rasterizer will perform
* anti-aliasing on the returned path.
*
* @param fractionalMetrics <code>false</code> for adjusting glyph
* positions to the raster grid of device space.
*
* @return the scaled and grid-fitted outline of the specified
* glyph, or <code>null</code> for bitmap fonts.
*/
public abstract GeneralPath getOutline(int glyph,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics);
/**
* Determines the advance width and height for a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is well
* possible that both values are non-zero, for example for rotated
* text or for Urdu fonts.
*/
public abstract void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance);
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public abstract float getAscent(float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal);
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public abstract float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
}
@@ -0,0 +1,161 @@
/* Fixed.java -- Fixed-point arithmetics for TrueType coordinates.
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.font.opentype.truetype;
/**
* A utility class for fixed-point arithmetics, where numbers are
* represented with 26 dot 6 digits. This representation is used by
* TrueType coordinates.
*
* <p>A good compiler will inline calls of methods in this class.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class Fixed
{
public static final int ONE = 1<<6;
/**
* The constructor is private so nobody can use it.
*/
private Fixed()
{
}
/**
* Multiplies two fixed-point numbers.
*/
public static int mul(int a, int b)
{
return (int) ((((long) a) * b) >> 6);
}
public static int div(int a, int b)
{
return (int) ((((long) a) << 6) / b);
}
public static int ceil(int a)
{
return (a + 63) & -64;
}
public static int floor(int a)
{
return a & -64;
}
/**
* Calculates the length of a fixed-point vector.
*/
public static int vectorLength(int x, int y)
{
int shift;
float fx, fy;
if (x == 0)
return Math.abs(y);
else if (y == 0)
return Math.abs(x);
/* Use the FPU. */
fx = ((float) x) / 64.0f;
fy = ((float) y) / 64.0f;
return (int) (Math.sqrt(fx * fx + fy * fy) * 64.0);
}
public static int intValue(int f)
{
return f >> 6;
}
public static float floatValue(int f)
{
return ((float) f) / 64;
}
public static double doubleValue(int f)
{
return ((double) f) / 64;
}
public static int valueOf(float f)
{
return (int) (f * 64);
}
public static int valueOf(double d)
{
return (int) (d * 64);
}
/**
* Makes a string representation of a fixed-point number.
*/
public static String toString(int f)
{
return String.valueOf(floatValue(f));
}
public static String toString(int x, int y)
{
StringBuffer sbuf = new StringBuffer(40);
sbuf.append('(');
sbuf.append(((float) x) / 64);
sbuf.append(", ");
sbuf.append(((float) y) / 64);
sbuf.append(')');
return sbuf.toString();
}
}
@@ -0,0 +1,437 @@
/* GlyphLoader.java -- Helper for loading TrueType glyph outlines.
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.font.opentype.truetype;
import java.awt.geom.AffineTransform;
import java.nio.ByteBuffer;
/**
* A class for loading scaled and hinted glyph outlines.
*
* <p><b>Lack of Thread Safety:</b> Glyph loaders are intentionally
* <i>not</i> safe to access from multiple concurrent
* threads. Synchronization needs to be performed externally. Usually,
* the font has already obtained a lock before calling the scaler,
* which in turn calls the GlyphLoader. It would thus be wasteful to
* acquire additional locks for the GlyphLoader.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class GlyphLoader
{
/**
* A helper object for locating glyph data. GlyphLocator is an
* abstract superclass, and there is a concretization for each glyph
* location table ('loca') format.
*/
private final GlyphLocator glyphLocator;
/**
* A helper object for measuring the advance width and height of a
* glyph.
*/
private final GlyphMeasurer glyphMeasurer;
/**
* The virtual machine for executing TrueType bytecodes.
*/
private final VirtualMachine vm;
/**
* The number of font units in one em. A typical value is 2048,
* but this depends on the font.
*/
private final int unitsPerEm;
private final int[] contourEndPoints;
private final byte[] pointFlags;
/**
* Constructs a GlyphLoader.
*/
GlyphLoader(GlyphLocator glyphLocator, VirtualMachine vm,
int unitsPerEm, int maxContours, int maxPoints,
GlyphMeasurer glyphMeasurer)
{
this.glyphLocator = glyphLocator;
this.glyphMeasurer = glyphMeasurer;
this.unitsPerEm = unitsPerEm;
this.vm = vm;
contourEndPoints = new int[maxContours];
pointFlags = new byte[maxPoints];
}
/**
* @param glyphIndex the number of the glyph whose outlines are to be
* retrieved.
*/
public void loadGlyph(int glyphIndex,
double pointSize,
AffineTransform transform,
boolean antialias,
Zone glyphZone)
{
glyphZone.setNumPoints(4);
loadSubGlyph(glyphIndex, pointSize, transform, antialias, glyphZone,
0, 0);
}
private void loadSubGlyph(int glyphIndex,
double pointSize,
AffineTransform transform,
boolean antialias,
Zone glyphZone,
int preTranslateX,
int preTranslateY)
{
ByteBuffer glyph;
int numContours;
int xMin, yMin, xMax, yMax;
byte flag;
glyph = glyphLocator.getGlyphData(glyphIndex);
if (glyph == null)
{
glyphZone.setNumPoints(4);
setPhantomPoints(glyphIndex, 0, glyphZone);
glyphZone.transform(pointSize, transform, unitsPerEm,
preTranslateX, preTranslateY);
return;
}
numContours = glyph.getShort();
xMin = glyph.getChar();
yMin = glyph.getChar();
xMax = glyph.getChar();
yMax = glyph.getChar();
if (numContours >= 0)
loadSimpleGlyph(glyphIndex, pointSize, transform, antialias,
numContours, glyph, glyphZone,
preTranslateX, preTranslateY);
else
loadCompoundGlyph(glyphIndex, pointSize, transform, antialias,
glyph, glyphZone,
preTranslateX, preTranslateY);
}
private void loadSimpleGlyph(int glyphIndex,
double pointSize, AffineTransform transform,
boolean antialias,
int numContours, ByteBuffer glyph,
Zone glyphZone,
int preTranslateX, int preTranslateY)
{
int numPoints;
int posInstructions, numInstructions;
boolean execInstructions;
execInstructions = vm.setup(pointSize, transform, antialias);
/* Load the contour end points and determine the number of
* points.
*/
for (int i = 0; i < numContours; i++)
contourEndPoints[i] = glyph.getChar();
if (numContours > 0)
numPoints = 1 + contourEndPoints[numContours - 1];
else
numPoints = 0;
glyphZone.setNumPoints(numPoints + 4);
numInstructions = glyph.getChar();
posInstructions = glyph.position();
glyph.position(posInstructions + numInstructions);
loadFlags(numPoints, glyph);
loadCoordinates(numPoints, glyph, glyphZone);
for (int i = 0; i < numContours; i++)
glyphZone.setContourEnd(contourEndPoints[i], true);
setPhantomPoints(glyphIndex, numPoints, glyphZone);
glyphZone.transform(pointSize, transform, unitsPerEm,
preTranslateX, preTranslateY);
if (execInstructions)
{
// FIXME: Hint the glyph.
}
}
private static final short ARGS_ARE_WORDS = 1;
private static final short ARGS_ARE_XY_VALUES = 2;
private static final short ROUND_XY_TO_GRID = 4;
private static final short WE_HAVE_A_SCALE = 8;
private static final short MORE_COMPONENTS = 32;
private static final short WE_HAVE_AN_X_AND_Y_SCALE = 64;
private static final short WE_HAVE_A_TWO_BY_TWO = 128;
private static final short WE_HAVE_INSTRUCTIONS = 256;
private static final short USE_MY_METRICS = 512;
private static final short OVERLAP_COMPOUND = 1024;
private static final short SCALED_COMPONENT_OFFSET = 2048;
private static final short UNSCALED_COMPONENT_OFFSET = 4096;
private void loadCompoundGlyph(int glyphIndex,
double pointSize,
AffineTransform transform,
boolean antialias,
ByteBuffer glyph,
Zone glyphZone,
int preTranslateX, int preTranslateY)
{
short flags;
int subGlyphIndex;
int metricsGlyphIndex;
Zone subGlyphZone = new Zone(glyphZone.getCapacity());
int arg1, arg2;
double a, b, c, d, e, f;
AffineTransform componentTransform = new AffineTransform();
/* By default, use the metrics of the compound glyph. The default
* is overridden if some component glyph has the USE_MY_METRICS
* flag set.
*/
metricsGlyphIndex = glyphIndex;
do
{
flags = glyph.getShort();
subGlyphIndex = glyph.getChar();
if ((flags & USE_MY_METRICS) != 0)
metricsGlyphIndex = subGlyphIndex;
if ((flags & ARGS_ARE_WORDS) != 0)
{
arg1 = glyph.getShort();
arg2 = glyph.getShort();
}
else
{
arg1 = glyph.get();
arg2 = glyph.get();
}
if ((flags & WE_HAVE_A_SCALE) != 0)
{
a = d = getDouble214(glyph);
b = c = 0.0;
}
else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0)
{
a = getDouble214(glyph);
d = getDouble214(glyph);
b = c = 0.0;
}
else if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0)
{
a = getDouble214(glyph);
b = getDouble214(glyph);
c = getDouble214(glyph);
d = getDouble214(glyph);
}
else
{
a = d = 1.0;
b = c = 0.0;
}
double m = Math.max(Math.abs(a), Math.abs(b));
double n = Math.max(Math.abs(c), Math.abs(d));
/* The Apple TrueType specification actually says that m is
* multiplied by two if
*
* abs(abs(a) - abs(c)) <= 33/65536,
*
* but this is probably a typo. On 2003-07-23, Sascha Brawer
* wrote an e-mail message to applefonts@apple.com, asking
* whether this might possibly be an error in the specification.
*/
if (Math.abs(Math.abs(a) - Math.abs(b)) <= 33.0/65536.0)
m = m * 2;
if (Math.abs(Math.abs(c) - Math.abs(d)) <= 33.0/65536.0)
n = n * 2;
if ((flags & ARGS_ARE_XY_VALUES) != 0)
{
e = m * arg1;
f = n * arg2;
}
else
e = f = 0.0;
componentTransform.setTransform(a, b, c, d, 0.0, 0.0);
// System.out.println("componentTransform = " + componentTransform
// + ", e=" + e + ", f=" + f);
componentTransform.concatenate(transform);
int pos = glyph.position();
int lim = glyph.limit();
loadSubGlyph(subGlyphIndex, pointSize, componentTransform,
antialias, subGlyphZone,
Math.round((float) e + preTranslateX),
Math.round(-((float) f + preTranslateY)));
glyphZone.combineWithSubGlyph(subGlyphZone, 4);
glyph.limit(lim).position(pos);
}
while ((flags & MORE_COMPONENTS) != 0);
setPhantomPoints(metricsGlyphIndex, glyphZone.getSize() - 4, glyphZone);
}
private double getDouble214(ByteBuffer buf)
{
return ((double) buf.getShort()) / (1 << 14);
}
/**
* Loads the per-point flags of a glyph into the
* <code>pointFlags</code> field.
*/
private void loadFlags(int numPoints, ByteBuffer glyph)
{
byte flag;
int numRepetitions;
for (int i = 0; i < numPoints; i++)
{
pointFlags[i] = flag = glyph.get();
if ((flag & 8) != 0)
{
numRepetitions = ((int) glyph.get()) & 0xff;
while (numRepetitions > 0)
{
pointFlags[++i] = flag;
--numRepetitions;
}
}
}
}
private void loadCoordinates(int numPoints, ByteBuffer glyph,
Zone glyphZone)
{
int x, y;
byte flag;
x = 0;
for (int i = 0; i < numPoints; i++)
{
flag = pointFlags[i];
if ((flag & 2) == 0)
{
if ((flag & 16) == 0)
x += glyph.getShort();
}
else
{
if ((flag & 16) != 0)
x += (glyph.get() & 0xff);
else
x -= (glyph.get() & 0xff);
}
glyphZone.setOriginalX(i, x);
glyphZone.setOnCurve(i, (flag & 1) == 1);
}
y = 0;
for (int i = 0; i < numPoints; i++)
{
flag = pointFlags[i];
if ((flag & 4) == 0)
{
if ((flag & 32) == 0)
y += glyph.getShort();
}
else
{
if ((flag & 32) != 0)
y += (glyph.get() & 0xff);
else
y -= (glyph.get() & 0xff);
}
glyphZone.setOriginalY(i, -y);
}
}
private void setPhantomPoints(int glyphIndex, int numPoints,
Zone glyphZone)
{
/* Phantom point 0: Character origin. */
glyphZone.setOriginalX(numPoints, 0);
glyphZone.setOriginalY(numPoints, 0);
/* Phantom point 1: Horizontal advance point. */
glyphZone.setOriginalX(numPoints + 1,
glyphMeasurer.getAdvanceWidth(glyphIndex, true));
glyphZone.setOriginalY(numPoints + 1,
glyphMeasurer.getAdvanceHeight(glyphIndex, true));
/* Phantom point 2: Vertical origin. */
int vertX = glyphMeasurer.getAscent(/* vertical */ false);
int vertY = glyphMeasurer.getAscent(/* horizontal */ true);
glyphZone.setOriginalX(numPoints + 2, vertX);
glyphZone.setOriginalY(numPoints + 2, vertY);
/* Phantom point 3: Vertical advance point. */
glyphZone.setOriginalX(numPoints + 3,
vertX + glyphMeasurer.getAdvanceWidth(glyphIndex, false));
glyphZone.setOriginalY(numPoints + 3,
vertY + glyphMeasurer.getAdvanceHeight(glyphIndex, false));
}
}
@@ -0,0 +1,187 @@
/* GlyphLocator.java -- Locates outlines of TrueType glyphs.
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.font.opentype.truetype;
import java.awt.FontFormatException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
/**
* Locates glyph outlines in a TrueType or OpenType <code>glyf</code>
* table.
*
* @see <a href=
* "http://partners.adobe.com/asn/tech/type/opentype/loca.html"
* >Adobe&#x2019;s specification of the OpenType &#x2018;loca&#x2019;
* table</a>
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
abstract class GlyphLocator
{
/**
* The actual glyph data of the font, which is contained in the
* 'glyf' table.
*/
protected ByteBuffer glyfTable;
/**
* Creates a new GlyphLocator for a <code>loca</code> table.
*
* @param format the format of the <code>loca</code> table. The
* value must be 0 for two-byte offsets, or 1 for four-byte
* offsets. TrueType and OpenType fonts indicate the format in the
* <code>indexToLoc</code> field of the <a href=
* "http://partners.adobe.com/asn/tech/type/opentype/head.html"
* >font header</a>.
*
* @param loca the <code>loca</code> table of the font, which
* contains the position of each glyph in the <code>glyf</code>
* table.
*
* @param glyf the <code>glyf</code> table of the font, which
* contains the outline data of each glyph.
*
* @throws FontFormatException if <code>format</code> is neither 0
* nor 1.
*/
public static GlyphLocator forTable(int format, ByteBuffer loca,
ByteBuffer glyf)
throws FontFormatException
{
switch (format)
{
case 0:
return new GlyphLocator.TwoByte(loca, glyf);
case 1:
return new GlyphLocator.FourByte(loca, glyf);
default:
throw new FontFormatException("unsupported loca format");
}
}
/**
* Locates the outline data for a glyph.
*
* <p>For efficiency, the glyph locator does not create a new buffer
* for each invocation. Instead, this method always returns the same
* buffer object. Therefore, the data of a glyph must have been read
* completely before another glyph of the same font gets requested
* through this method.
*
* @param glyph the number of the glyph whose outlines are to be
* retrieved.
*
* @return a buffer whose position is set to the first byte of glyph
* data, and whose limit is set to disallow accessing any data that
* does not belong to the glyph. If there is no outline data for the
* requested glyph, as would be the case for the space glyph, the
* result will be <code>null</code>.
*/
public abstract ByteBuffer getGlyphData(int glyph);
/**
* A GlyphLocator that locates glyphs using two-byte offsets,
* interpreting <code>loca</code> tables of format 0.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
private final static class TwoByte
extends GlyphLocator
{
final CharBuffer indexToLoc;
TwoByte(ByteBuffer loca, ByteBuffer glyf)
{
this.glyfTable = glyf;
indexToLoc = loca.asCharBuffer();
}
public ByteBuffer getGlyphData(int glyph)
{
int offset, limit;
offset = ((int) indexToLoc.get(glyph)) << 1;
limit = ((int) indexToLoc.get(glyph + 1)) << 1;
if (offset >= limit)
return null;
glyfTable.limit(limit).position(offset);
return glyfTable;
}
}
/**
* A GlyphLocator that locates glyphs using four-byte offsets,
* interpreting <code>loca</code> tables of format 1.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
private final static class FourByte
extends GlyphLocator
{
final IntBuffer indexToLoc;
FourByte(ByteBuffer loca, ByteBuffer glyf)
{
this.glyfTable = glyf;
indexToLoc = loca.asIntBuffer();
}
public ByteBuffer getGlyphData(int glyph)
{
int offset, limit;
offset = indexToLoc.get(glyph);
limit = indexToLoc.get(glyph + 1);
if (offset >= limit)
return null;
glyfTable.limit(limit).position(offset);
return glyfTable;
}
}
}
@@ -0,0 +1,228 @@
/* GlyphMeasurer.java -- Helper for measuring TrueType glyphs.
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.font.opentype.truetype;
import java.awt.FontFormatException;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
/**
* A class for measuring TrueType and OpenType glyphs.
*
* <p><b>Lack of Thread Safety:</b> Glyph measurers are intentionally
* <i>not</i> safe to access from multiple concurrent
* threads. Synchronization needs to be performed externally. Usually,
* the font has already obtained a lock before calling the scaler,
* which in turn calls the GlyphMeasurer. It would thus be wasteful to
* acquire additional locks for the GlyphMeasurer.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class GlyphMeasurer
{
/**
* A view buffer that allows accessing the contents of the
* font&#x2019;s <code>hmtx</code> table as shorts.
*/
private final ShortBuffer horizontalGlyphMetrics;
/**
* A view buffer that allows accessing the contents of the
* font&#x2019;s <code>vmtx</code> table as shorts.
*/
private final ShortBuffer verticalGlyphMetrics;
private final int numLongHorizontalMetricsEntries;
private final int numLongVerticalMetricsEntries;
private final int horizontalAscent;
private final int verticalAscent;
private final int horizontalDescent;
private final int verticalDescent;
private final int horizontalLineGap;
/**
* Constructs a GlyphMeasurer from TrueType/OpenType font tables.
*
* @param hhea the <code>hhea</code> table, which contains
* information about horizontal metrics that is common to all
* glyphs.
*
* @param hmtx the <code>hmtx</code> table, which contains
* glyph-specific information about horizontal metrics.
*
* @param vhea the <code>vhea</code> table, which contains
* information about vertical metrics that is common to all
* glyphs. If a font does not provide such a table, pass
* <code>null</code>.
*
* @param vmtx the <code>vmtx</code> table, which contains
* glyph-specific information about vertical metrics. If a font
* does not provide such a table, pass <code>null</code>.
*/
GlyphMeasurer(ByteBuffer hhea, ByteBuffer hmtx,
ByteBuffer vhea, ByteBuffer vmtx)
throws FontFormatException
{
if ((hhea.getInt(0) != 0x00010000) || (hhea.getInt(30) != 0))
throw new FontFormatException("unsupported hhea format");
horizontalAscent = hhea.getShort(4);
horizontalDescent = hhea.getShort(6);
horizontalLineGap = hhea.getShort(8);
numLongHorizontalMetricsEntries = hhea.getChar(34);
horizontalGlyphMetrics = hmtx.asShortBuffer();
if (vhea != null)
{
verticalAscent = vhea.getShort(4);
verticalDescent = vhea.getShort(6);
numLongVerticalMetricsEntries = vhea.getChar(34);
verticalGlyphMetrics = vmtx.asShortBuffer();
}
else
{
verticalAscent = /* advanceWidthMax */ hhea.getChar(10) / 2;
verticalDescent = -verticalAscent;
numLongVerticalMetricsEntries = 0;
verticalGlyphMetrics = null;
}
}
/**
* Returns the distance from the baseline to the highest ascender.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the maximal ascent, in font units.
*/
public int getAscent(boolean horizontal)
{
return horizontal ? horizontalAscent : verticalAscent;
}
/**
* Returns the distance from the baseline to the lowest descender.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the maximal descent, in font units.
*/
public int getDescent(boolean horizontal)
{
return horizontal ? horizontalDescent : verticalDescent;
}
/**
* Returns the typographic line gap.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the line gap, in font units.
*/
public int getLineGap(boolean horizontal)
{
return horizontalLineGap;
}
/**
* Determines the advance width of a glyph, without considering
* hinting.
*
* @param glyphIndex the index of the glyph whose advance width is
* to be determined.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the advance width, in font units.
*/
public int getAdvanceWidth(int glyphIndex, boolean horizontal)
{
if (!horizontal)
return 0;
glyphIndex = Math.min(glyphIndex,
numLongHorizontalMetricsEntries - 1);
return horizontalGlyphMetrics.get(glyphIndex << 1);
}
/**
* Determines the advance width of a glyph, without considering
* hinting.
*
* @param glyphIndex the index of the glyph whose advance width is
* to be determined.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the advance width, in font units.
*/
public int getAdvanceHeight(int glyphIndex, boolean horizontal)
{
if (horizontal)
return 0;
/* If a font does not provide vertical glyph metrics, advance
* by the height of one horizontal line.
*/
if (verticalGlyphMetrics == null)
return horizontalAscent - horizontalDescent + horizontalLineGap;
glyphIndex = Math.min(glyphIndex,
numLongVerticalMetricsEntries - 1);
return verticalGlyphMetrics.get(glyphIndex << 1);
}
}
@@ -0,0 +1,372 @@
/* TrueTypeScaler.java -- Font scaler for TrueType outlines.
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.font.opentype.truetype;
import gnu.java.awt.font.opentype.Scaler;
import java.awt.FontFormatException;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;
/**
* A scaler for fonts whose outlines are described in the TrueType
* format.
*
* <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
* <i>not</i> safe to access from multiple concurrent threads.
* Synchronization needs to be performed externally. Usually, the font
* that uses this scaler already has obtained a lock before calling
* the scaler.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public final class TrueTypeScaler
extends Scaler
{
/**
* The TrueType or OpenType table that contains the glyph outlines.
*/
private ByteBuffer glyfTable;
/**
* A helper object for loading glyph outlines.
*/
private GlyphLoader glyphLoader;
/**
* A helper object for measuring the advance width and height of a
* glyph.
*/
private final GlyphMeasurer glyphMeasurer;
private final Zone glyphZone;
/**
* The number of units per em. A typical value is 2048, but some
* font use other numbers as well.
*/
private int unitsPerEm;
/**
* Constructs a new TrueTypeScaler.
*
* @param unitsPerEm the number of font units per em. This value can
* be retrieved from the font&#x2019;s <code>head</code> table.
*
* @param maxp the <code>maxp</code> table of the font, which
* contains various constants needed for setting up the virtual
* machine that interprets TrueType bytecodes.
*
* @param controlValueTable the <code>cvt</code> table of the font,
* which contains the initial values of the control value table.
*
* @param fpgm the <code>fpgm</code> table of the font, which
* contains a font program that is executed exactly once. The
* purpose of the font program is to define functions and to patch
* the interpreter.
*
* @param locaFormat the format of the <code>loca</code> table. The
* value must be 0 for two-byte offsets, or 1 for four-byte
* offsets. TrueType and OpenType fonts indicate the format in the
* <code>indexToLoc</code> field of the <a href=
* "http://partners.adobe.com/asn/tech/type/opentype/head.html"
* >font header</a>.
*
* @param loca the <code>loca</code> table of the font, which
* contains for each glyph the offset of its outline data
* in <code>glyf</code>.
*
* @param glyf the <code>glyf</code> table of the font, which
* contains the outline data for all glyphs in the font.
*
* @param preProgram the <code>prep</code> table of the font, which
* contains a program that is executed whenever the point size or
* the device transform have changed. This program is called
* pre-program because it gets executed before the instructions of
* the individual glyphs. If the font does not contain a
* pre-program, pass <code>null</code>.
*
* @throws FontFormatException if <code>format</code> is neither 0
* nor 1.
*/
public TrueTypeScaler(int unitsPerEm,
ByteBuffer hhea,
ByteBuffer htmx,
ByteBuffer vhea,
ByteBuffer vtmx,
ByteBuffer maxp,
ByteBuffer controlValueTable,
ByteBuffer fpgm,
int locaFormat, ByteBuffer loca,
ByteBuffer glyf,
ByteBuffer preProgram)
throws FontFormatException
{
int maxContours, maxPoints;
VirtualMachine vm;
maxContours = Math.max(/* maxContours */ (int) maxp.getChar(8),
/* maxCompositeContours */ (int) maxp.getChar(12))
+ /* fix for some broken fonts */ 8;
maxPoints = Math.max(/* maxPoints */ (int) maxp.getChar(6),
/* maxCompositePoints */ (int) maxp.getChar(10))
+ /* fix for some broken fonts */ 12;
glyphZone = new Zone(maxPoints + /* four phantom points */ 4);
this.glyfTable = glyf;
vm = new VirtualMachine(unitsPerEm, maxp,
controlValueTable, fpgm,
preProgram);
GlyphLocator locator = GlyphLocator.forTable(locaFormat, loca, glyf);
glyphMeasurer = new GlyphMeasurer(hhea, htmx, vhea, vtmx);
glyphLoader = new GlyphLoader(locator, vm, unitsPerEm,
maxContours, maxPoints,
glyphMeasurer);
this.unitsPerEm = unitsPerEm;
}
/**
* Retrieves the scaled outline of a glyph, adjusting control points
* to the raster grid if necessary.
*
* @param glyphIndex the glyph number whose outline is retrieved.
*
* @param pointSize the point size for the glyph.
*
* @param deviceTransform an affine transformation for the device.
*
* @param antialias whether or not the rasterizer will perform
* anti-aliasing on the returned path.
*
* @param fractionalMetrics <code>false</code> for adjusting glyph
* positions to the raster grid of device space.
*/
public GeneralPath getOutline(int glyphIndex,
float pointSize,
AffineTransform deviceTransform,
boolean antialias,
boolean fractionalMetrics)
{
glyphLoader.loadGlyph(glyphIndex, pointSize, deviceTransform,
antialias, glyphZone);
return glyphZone.getPath();
}
/**
* Determines the advance width and height for a glyph.
*
* @param glyphIndex the glyph whose advance width and height is to
* be determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is possible
* that both values are non-zero, for example if
* <code>transform</code> is a rotation, or in the case of Urdu
* fonts.
*/
public void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance)
{
double x, y;
double scaleFactor = (double) pointSize / unitsPerEm;
/* FIXME: Should grid-fit if needed. Also, use cache if present
* in the font.
*/
advance.setLocation(
scaleFactor * glyphMeasurer.getAdvanceWidth(glyphIndex, horizontal),
scaleFactor * glyphMeasurer.getAdvanceHeight(glyphIndex, horizontal));
transform.transform(advance, advance);
}
/**
* Scales a value from font units to pixels, given the point size
* and the transform.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution.
*
* @param fractionalMetrics <code>true</code> for fractional
* metrics, <code>false</code> for rounding the result to a pixel
* boundary.
*
* @param horizontal <code>true</code> if the <code>funits</code>
* value is along the x axis, <code>false</code> if it is along the
* y axis.
*/
private float scaleFromFUnits(int funits,
float pointSize,
AffineTransform transform,
boolean fractionalMetrics,
boolean horizontal)
{
double s;
s = (double) pointSize / unitsPerEm;
if (transform != null)
s *= horizontal ? transform.getScaleY() : transform.getScaleX();
s *= funits;
if (!fractionalMetrics)
s = Math.round(s);
return (float) s;
}
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public float getAscent(float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal)
{
/* Note that the ascent is orthogonal to the direction of line
* layout: If the line direction is horizontal, the measurement of
* ascent is along the vertical axis, and vice versa.
*/
return scaleFromFUnits(glyphMeasurer.getAscent(horizontal),
pointSize,
transform,
fractionalMetrics,
/* reverse */ !horizontal);
}
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal)
{
/* Note that the descent is orthogonal to the direction of line
* layout: If the line direction is horizontal, the measurement of
* descent is along the vertical axis, and vice versa.
*/
return scaleFromFUnits(glyphMeasurer.getDescent(horizontal),
pointSize,
transform,
fractionalMetrics,
/* reverse */ !horizontal);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,243 @@
/* Zone.java -- A collection of points with some additional information.
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.font.opentype.truetype;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
/**
* A collection of points with some additional information.
*/
final class Zone
{
private final int[] pos;
private final int[] origPos;
private final byte[] flags;
private int numPoints;
private static final int FLAG_TOUCHED_X = 1;
private static final int FLAG_TOUCHED_Y = 2;
private static final int FLAG_ON_CURVE = 4;
private static final int FLAG_CONTOUR_END = 8;
public Zone(int maxNumPoints)
{
origPos = new int[maxNumPoints * 2];
pos = new int[maxNumPoints * 2];
flags = new byte[maxNumPoints];
}
public int getCapacity()
{
return flags.length;
}
public int getSize()
{
return numPoints;
}
public int getX(int point)
{
return pos[2 * point];
}
public void setX(int point, int value, boolean touch)
{
pos[2 * point] = value;
if (touch)
flags[point] |= FLAG_TOUCHED_X;
}
public void setY(int point, int value, boolean touch)
{
pos[2 * point + 1] = value;
if (touch)
flags[point] |= FLAG_TOUCHED_Y;
}
public int getY(int point)
{
return pos[2 * point + 1];
}
public int getOriginalX(int point)
{
return origPos[2 * point];
}
public int getOriginalY(int point)
{
return origPos[2 * point + 1];
}
public void setOriginalX(int point, int x)
{
origPos[2 * point] = x;
}
public void setOriginalY(int point, int y)
{
origPos[2 * point + 1] = y;
}
public void setNumPoints(int numPoints)
{
this.numPoints = numPoints;
for (int i = 0; i < numPoints; i++)
flags[i] = 0;
for (int i = 0; i < 2 * numPoints; i++)
origPos[i] = pos[i] = 0;
}
public boolean isOnCurve(int point)
{
return (flags[point] & FLAG_ON_CURVE) != 0;
}
public void setOnCurve(int point, boolean onCurve)
{
if (onCurve)
flags[point] |= FLAG_ON_CURVE;
else
flags[point] &= ~FLAG_ON_CURVE;
}
public boolean isContourEnd(int point)
{
return (flags[point] & FLAG_CONTOUR_END) != 0;
}
public void setContourEnd(int point, boolean segEnd)
{
if (segEnd)
flags[point] |= FLAG_CONTOUR_END;
else
flags[point] &= ~FLAG_CONTOUR_END;
}
void transform(double pointSize, AffineTransform deviceTransform,
int unitsPerEm, int preTranslateX, int preTranslateY)
{
double scaleX, scaleY, shearX, shearY;
double factor;
factor = pointSize / (double) unitsPerEm;
scaleX = deviceTransform.getScaleX() * factor;
scaleY = deviceTransform.getScaleY() * factor;
shearX = deviceTransform.getShearX() * factor;
shearY = deviceTransform.getShearY() * factor;
for (int i = 0; i < numPoints; i++)
{
int x = origPos[2 * i] + preTranslateX;
int y = origPos[2 * i + 1] + preTranslateY;
origPos[2*i] = pos[2 * i] = Fixed.valueOf(scaleX * x + shearX * y);
origPos[2*i+1] = pos[2 * i + 1] = Fixed.valueOf(shearY * x + scaleY * y);
}
}
void combineWithSubGlyph(Zone zone, int numPhantomPoints)
{
int offset = this.numPoints - numPhantomPoints;
int count = zone.numPoints;
System.arraycopy(zone.origPos, 0, this.origPos, 2 * offset,
count * 2);
System.arraycopy(zone.pos, 0, this.pos, 2 * offset,
count * 2);
System.arraycopy(zone.flags, 0, this.flags, offset, count);
this.numPoints += count - numPhantomPoints;
}
private void dump()
{
for (int i = 0; i < numPoints; i++)
{
System.out.print(" " + i + ": ");
System.out.print(Fixed.toString(pos[i*2], pos[i*2+1]));
System.out.print(' ');
System.out.print(Fixed.toString(origPos[i*2], origPos[i*2+1]));
System.out.print(' ');
if (isOnCurve(i))
System.out.print('.');
else
System.out.print('c');
if (isContourEnd(i))
System.out.print('E');
System.out.println();
if (isContourEnd(i))
System.out.println();
}
}
public PathIterator getPathIterator()
{
return new ZonePathIterator(this);
}
public GeneralPath getPath()
{
GeneralPath p = new GeneralPath(GeneralPath.WIND_NON_ZERO, numPoints);
p.append(getPathIterator(), /* connect */ false);
return p;
}
}
@@ -0,0 +1,391 @@
/* ZonePathIterator.java -- A PathIterator over glyph zones.
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.font.opentype.truetype;
import java.awt.geom.PathIterator;
/**
* A PathIterator that enumerates the non-phantom points in a zone.
*
* <p><b>Lack of thread safety:</b> Instances of this class are
* <i>not</i> safe to access from multiple concurrent threads.
*
* @see Zone
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class ZonePathIterator
implements PathIterator
{
/**
* If <code>state</code> has this value, <code>currentSegment</code>
* will emit a <code>SEG_LINETO</code> or <code>SEG_QUADTO</code> segment
* to the current point. For a discussion of subtleties of on-curve
* and off-curve points, please refer to the documentation for
* {@link #getSegment}.
*/
private static final int EMIT_SEGMENT = 0;
/**
* If <code>state</code> has this value, <code>currentSegment</code>
* will emit a <code>SEG_CLOSE</code> in order to close the sub-path
* for the current contour.
*/
private static final int EMIT_CLOSE = 1;
/**
* If <code>state</code> has this value, <code>currentSegment</code>
* will emit a <code>SEG_MOVETO</code> segment to the first point in
* the current contour. If the first point is off-curve, a suitable
* on-curve point is calculated.
*
* @see #getStartSegment
*/
private static final int EMIT_MOVETO = 2;
/**
* The state of the iterator, which is one of
* <code>EMIT_SEGMENT</code>, <code>EMIT_CLOSE</code>, or
* <code>EMIT_MOVETO</code>.
*/
private int state;
/**
* The zone whose segments are enumerated by this iterator.
*/
private Zone zone;
/**
* The total number of points in the zone, not including the four
* phantom points at its end.
*/
private int numPoints;
/**
* The number of the current point.
*/
private int curPoint;
/**
* The number of the first point in the current contour.
*/
private int contourStart;
/**
* Constructs a ZonePathIterator for the specified zone.
*
* @param zone the zone whose segments will be enumerated
* by this iterator.
*/
ZonePathIterator(Zone zone)
{
this.zone = zone;
numPoints = zone.getSize() - /* four phantom points */ 4;
// The first segment that needs to be emitted is a SEG_MOVETO.
state = EMIT_MOVETO;
}
/**
* Returns the winding rule. TrueType glyphs always use the non-zero
* winding rule, so this method will always return {@link
* PathIterator#WIND_NON_ZERO}.
*/
public int getWindingRule()
{
return PathIterator.WIND_NON_ZERO;
}
public boolean isDone()
{
return (state != EMIT_CLOSE) && (curPoint >= numPoints);
}
public void next()
{
boolean onCurve;
/* If the current point is the end of a segment, and no SEG_CLOSE
* has been emitted yet, this will be the next segment.
*/
if (zone.isContourEnd(curPoint) && (state != EMIT_CLOSE))
{
state = EMIT_CLOSE;
return;
}
/* If the previously emitted segment was a SEG_CLOSE, we are now
* at the beginning of a new contour.
*/
if (state == EMIT_CLOSE)
{
contourStart = ++curPoint;
state = EMIT_MOVETO;
return;
}
onCurve = zone.isOnCurve(curPoint);
/* If the last segment was a moveto, and the current point
* (which is the first point in the contour) is off-curve,
* we need to emit a quadto segment for the first point.
*/
if ((state == EMIT_MOVETO) && !onCurve)
{
state = EMIT_SEGMENT;
return;
}
curPoint++;
/* If the last point has been off-curve, and the now current
* point is on-curve, the last segment was a quadto that
* had the now current point at its end. In this case, we can
* skip a segment.
*/
if (!onCurve && zone.isOnCurve(curPoint))
{
/* But if the skipped point is the end of a contour, we must not
* skip the SEG_CLOSE. An example where this matters is the 'o'
* glyph in the Helvetica font face that comes with MacOS X
* 10.1.5.
*/
if (zone.isContourEnd(curPoint))
{
state = EMIT_CLOSE;
return;
}
curPoint++;
}
state = EMIT_SEGMENT;
}
/**
* Determines the successor of the current point in the current
* contour. The successor of the last point in a contour is the
* start of that contour.
*
* @return the number of the point that follows the current point in
* the same contour.
*/
private int getSuccessor(int p)
{
if (zone.isContourEnd(p))
return contourStart;
else
return p + 1;
}
/**
* Retrieves the current path segment using single-precision
* coordinate values.
*/
public int currentSegment(float[] coords)
{
switch (state)
{
case EMIT_CLOSE:
return PathIterator.SEG_CLOSE;
case EMIT_MOVETO:
return getStartSegment(curPoint, coords);
default:
return getSegment(curPoint, coords);
}
}
/**
* A helper array that is used by {@link
* #currentSegment(double[])}.
*/
float[] floats;
/**
* Retrieves the current path segment using double-precision
* coordinate values.
*/
public int currentSegment(double[] coords)
{
if (floats == null)
floats = new float[6];
int result;
result = currentSegment(floats);
for (int i = 0; i < 6; i++)
coords[i] = floats[i];
return result;
}
/**
* Returns the segment for the specified point.
*
* <p><img src="doc-files/ZonePathIterator-1.png" width="426"
* height="194" alt="An example curve" /></p>
*
* <p>If <code>cur</code> is an on-curve point, the returned segment
* is a straight line to <code>cur</code>. In the illustration, this
* would be the case for <code>cur = 4</code>.</p>
*
* <p>If <code>cur</code> is an off-curve point, and
* <code>cur</code>&#x2019;s successor <code>succ</code> is also
* off-curve, the returned segment is a quadratic B&eacute;zier
* spline whose control point is <code>cur</code>, and whose end
* point is located at the middle of the line connecting
* <code>cur</code> and <code>succ</code>. In the illustration,
* this would be the case for <code>cur = 5</code>.</p>
*
* <p>If <code>cur</code> is an off-curve point, and
* <code>cur</code>&#x2019;s successor <code>succ</code> is
* on-curve, the returned segment is a quadratic B&eacute;zier
* spline whose control point is <code>cur</code>, and whose end
* point is <code>succ</code>. In the illustration, this would
* be the case for <code>cur = 6</code>.</p>
*
* @return either <code>PathIterator.SEG_LINETO</code> or
* <code>PathIterator.SEG_QUADTO</code>.
*/
private int getSegment(int cur, float[] coords)
{
int curX, curY;
int succ, succX, succY;
curX = zone.getX(cur);
curY = zone.getY(cur);
coords[0] = Fixed.floatValue(curX);
coords[1] = Fixed.floatValue(curY);
if (zone.isOnCurve(cur))
return PathIterator.SEG_LINETO;
succ = getSuccessor(cur);
succX = zone.getX(succ);
succY = zone.getY(succ);
if (zone.isOnCurve(succ))
{
coords[2] = Fixed.floatValue(succX);
coords[3] = Fixed.floatValue(succY);
}
else
{
coords[2] = Fixed.floatValue((curX + succX) / 2);
coords[3] = Fixed.floatValue((curY + succY) / 2);
}
return PathIterator.SEG_QUADTO;
}
/**
* Returns the start segment for the contour which starts
* at the specified point.
*
* <p>If the contour starts with an on-curve point, the returned
* segment is a <code>SEG_MOVETO</code> to that point.</p>
*
* <p>If the contour starts with an off-curve point, and the contour
* ends with an on-curve point, the returned segment is a
* <code>SEG_MOVETO</code> to the end point.</p>
*
* <p>If the contour starts with an off-curve point, and the contour
* also ends with an off-curve point, the returned segment is a
* <code>SEG_MOVETO</code> to the location at the middle between the
* start and end points of the contour.</p>
*
* @return <code>PathIterator.SEG_MOVETO</code>.
*/
private int getStartSegment(int contourStart, float[] coords)
{
int x, y;
if (zone.isOnCurve(contourStart))
{
x = zone.getX(contourStart);
y = zone.getY(contourStart);
}
else
{
/* Find the last point of the current contour. */
int contourEnd = contourStart;
while (!zone.isContourEnd(contourEnd))
++contourEnd;
if (zone.isOnCurve(contourEnd))
{
/* An example is the 'o' glyph of the Helvetica which comes
* with Apple MacOS X 10.1.5.
*/
x = zone.getX(contourEnd);
y = zone.getY(contourEnd);
}
else
{
x = (zone.getX(contourStart) + zone.getX(contourEnd)) / 2;
y = (zone.getY(contourStart) + zone.getY(contourEnd)) / 2;
}
}
coords[0] = Fixed.floatValue(x);
coords[1] = Fixed.floatValue(y);
return PathIterator.SEG_MOVETO;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB