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:
@@ -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>“Univers Light”</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>“Univers”</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>“Light”</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>“Helvetica-Bold”</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’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’ 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 “Univers”.
|
||||
*/
|
||||
public static final int NAME_FAMILY = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Specified the name of the font inside its family, for
|
||||
* example “Light”.
|
||||
*/
|
||||
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
|
||||
* “Univers Light”
|
||||
*/
|
||||
public static final int NAME_FULL = 4;
|
||||
|
||||
|
||||
public static final int NAME_VERSION = 5;
|
||||
|
||||
|
||||
/**
|
||||
* Specifies the PostScript name of a font, for example
|
||||
* “Univers-Light”.
|
||||
*/
|
||||
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>’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>"MacRoman"</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’s
|
||||
* OpenType specification</a>
|
||||
*
|
||||
* @see <a
|
||||
* href="http://developer.apple.com/fonts/TTRefMan/">Apple’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>“Univers”</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>“Light”</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>“Univers Light”</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>“Univers-Light”</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’s name table, or <code>null</code> if this
|
||||
* table has not yet been accessed.
|
||||
*/
|
||||
private ByteBuffer nameTable;
|
||||
|
||||
|
||||
/**
|
||||
* Extracts a String from the font’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’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’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 “hints”) 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’s specification of the OpenType ‘loca’
|
||||
* 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’s <code>hmtx</code> table as shorts.
|
||||
*/
|
||||
private final ShortBuffer horizontalGlyphMetrics;
|
||||
|
||||
|
||||
/**
|
||||
* A view buffer that allows accessing the contents of the
|
||||
* font’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’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>’s successor <code>succ</code> is also
|
||||
* off-curve, the returned segment is a quadratic Bé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>’s successor <code>succ</code> is
|
||||
* on-curve, the returned segment is a quadratic Bé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;
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Reference in New Issue
Block a user