Imported GNU Classpath 0.90

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

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

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

From-SVN: r113887
This commit is contained in:
Mark Wielaard 2006-05-18 17:29:21 +00:00
parent eaec4980e1
commit 4f9533c772
1640 changed files with 126485 additions and 104808 deletions

View file

@ -0,0 +1,313 @@
/* FontDelegate.java -- Interface implemented by all font delegates.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.text.CharacterIterator;
import java.util.Locale;
/**
* The interface that all font delegate objects implement,
* irrespective of where they get their information from.
*
* <p><b>Thread Safety:</b> All classes that implement the
* <code>FontDelegate</code> interface must allow calling these
* methods from multiple concurrent threads. The delegates are
* responsible for performing the necessary synchronization.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public interface FontDelegate
{
/**
* Returns the full name of this font face in the specified
* locale, for example <i>&#x201c;Univers Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the face name.
*/
public String getFullName(Locale locale);
/**
* Returns the name of the family to which this font face belongs,
* for example <i>&#x201c;Univers&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the family name.
*/
public String getFamilyName(Locale locale);
/**
* Returns the name of this font face inside the family, for example
* <i>&#x201c;Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the name of the face inside its family.
*/
public String getSubFamilyName(Locale locale);
/**
* Returns the PostScript name of this font face, for example
* <i>&#x201c;Helvetica-Bold&#x201d;</i>.
*
* @return the PostScript name, or <code>null</code> if the font
* does not provide a PostScript name.
*/
public String getPostScriptName();
/**
* Returns the number of glyphs in this font face.
*/
public int getNumGlyphs();
/**
* Returns the index of the glyph which gets displayed if the font
* cannot map a Unicode code point to a glyph. Many fonts show this
* glyph as an empty box.
*/
public int getMissingGlyphCode();
/**
* Creates a GlyphVector by mapping each character in a
* CharacterIterator to the corresponding glyph.
*
* <p>The mapping takes only the font&#x2019;s <code>cmap</code>
* tables into consideration. No other operations (such as glyph
* re-ordering, composition, or ligature substitution) are
* performed. This means that the resulting GlyphVector will not be
* correct for text in languages that have complex
* character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or
* Thai.
*
* @param font the font object that the created GlyphVector
* will return when it gets asked for its font. This argument is
* needed because the public API works with java.awt.Font,
* not with some private delegate like OpenTypeFont.
*
* @param frc the font rendering parameters that are used for
* measuring glyphs. The exact placement of text slightly depends on
* device-specific characteristics, for instance the device
* resolution or anti-aliasing. For this reason, any measurements
* will only be accurate if the passed
* <code>FontRenderContext</code> correctly reflects the relevant
* parameters. Hence, <code>frc</code> should be obtained from the
* same <code>Graphics2D</code> that will be used for drawing, and
* any rendering hints should be set to the desired values before
* obtaining <code>frc</code>.
*
* @param ci a CharacterIterator for iterating over the
* characters to be displayed.
*/
public GlyphVector createGlyphVector(Font font,
FontRenderContext frc,
CharacterIterator ci);
/**
* Determines the advance width and height for a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is well
* possible that both values are non-zero, for example for rotated
* text or for Urdu fonts.
*/
public void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance);
/**
* Returns the shape of a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts, this
* parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional
* metrics, <code>false</code> for rounding the result to a pixel
* boundary.
*
* @return the scaled and grid-fitted outline of the specified
* glyph, or <code>null</code> for bitmap fonts.
*/
public GeneralPath getGlyphOutline(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics);
/**
* Returns a name for the specified glyph. This is useful for
* generating PostScript or PDF files that embed some glyphs of a
* font.
*
* <p><b>Names are not unique:</b> Under some rare circumstances,
* the same name can be returned for different glyphs. It is
* therefore recommended that printer drivers check whether the same
* name has already been returned for antoher glyph, and make the
* name unique by adding the string ".alt" followed by the glyph
* index.</p>
*
* <p>This situation would occur for an OpenType or TrueType font
* that has a <code>post</code> table of format 3 and provides a
* mapping from glyph IDs to Unicode sequences through a
* <code>Zapf</code> table. If the same sequence of Unicode
* codepoints leads to different glyphs (depending on contextual
* position, for example, or on typographic sophistication level),
* the same name would get synthesized for those glyphs.
*
* @param glyphIndex the glyph whose name the caller wants to
* retrieve.
*/
public String getGlyphName(int glyphIndex);
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public float getAscent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -0,0 +1,235 @@
/* MacResourceFork.java -- Parses MacOS resource forks.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype;
import java.nio.ByteBuffer;
/**
* A class for accessing data that is stored in the resource fork of
* Macintosh files. Writing resource forks is currently not supported.
*
* <p>The gnu.java.awt.font package uses this class for accessing
* fonts in the MacOS X ".dfont" format, which is is a file in the
* format of a Macintosh resource fork, but stored in the normal data
* fork of the file.
*
* <p>The implementation has been designed to work efficiently with
* the virtual memory subsystem. It is recommended to pass an
* instance of {@link java.nio.MappedByteBuffer} to the constructor.
*
* <p>Thread Safety: All access is synchronized on the ByteBuffer
* that is passed to the constructor.
*
* @see <a href=
* "http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html"
* >Apple&#x2019; developer documentation about the Resource File
* Format</a>
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class MacResourceFork
{
int[] types;
Resource[][] resources;
ByteBuffer buf;
public MacResourceFork(ByteBuffer buf)
{
int typeListOffset;
int refListOffset;
int nameListOffset;
int mapOffset, mapLen;
int dataOffset, dataLen;
int numTypes;
synchronized (buf)
{
buf = buf.duplicate();
this.buf = buf;
buf.position(0);
dataOffset = buf.getInt();
mapOffset = buf.getInt();
dataLen = buf.getInt();
mapLen = buf.getInt();
buf.position(mapOffset + 24);
refListOffset = mapOffset + buf.getChar();
nameListOffset = mapOffset + buf.getChar();
numTypes = buf.getChar() + 1;
types = new int[numTypes];
resources = new Resource[numTypes][];
/* Parse resource type list. */
typeListOffset = buf.position();
for (int i = 0; i < numTypes; i++)
{
buf.position(typeListOffset + 8 * i);
int resType = buf.getInt();
int numRes = buf.getChar() + 1;
types[i] = resType;
resources[i] = new Resource[numRes];
buf.position(refListOffset + buf.getChar());
for (int j = 0; j < numRes; j++)
{
short resID = buf.getShort();
int resNameOffset = nameListOffset + buf.getChar();
int resDataOffset = buf.getInt();
byte resAttr = (byte) (resDataOffset >> 24);
resDataOffset = dataOffset + (resDataOffset & 0x00ffffff);
buf.getInt(); /* skip four reserved bytes */
Resource rsrc = new Resource(buf, resType, resID, resDataOffset,
resNameOffset);
resources[i][j] = rsrc;
}
}
}
}
public Resource[] getResources(int type)
{
synchronized (buf)
{
for (int i = 0; i < types.length; i++)
{
if (types[i] == type)
return resources[i];
}
}
return null;
}
public Resource getResource(int type, short id)
{
Resource[] res;
synchronized (buf)
{
for (int i = 0; i < types.length; i++)
{
if (types[i] != type)
continue;
res = resources[i];
for (int j = 0; j < res.length; j++)
if (res[j].getID() == id)
return res[j];
}
}
return null;
}
/**
* A single resource that is contained in a resource fork.
*/
public static final class Resource
{
int type;
short id;
byte attribute;
int nameOffset;
int dataOffset;
ByteBuffer buf;
private Resource(ByteBuffer buf,
int type, short id, int dataOffset, int nameOffset)
{
this.buf = buf;
this.type = type;
this.id = id;
this.dataOffset = dataOffset;
this.nameOffset = nameOffset;
}
/**
* Returns the type of this resource.
*
* @return an <code>int</code> encoding a four-byte type tag,
* such as <code>0x464f4e54</code> for <code>'FONT'</code>.
*/
public int getType()
{
return type;
}
/**
* Returns the ID of this resource.
*/
public short getID()
{
return id;
}
/**
* Retrieves the content of the resource. Only one page of memory
* is touched, irrespective of the actual size of the resource.
*/
public ByteBuffer getContent()
{
synchronized (buf)
{
buf.limit(buf.capacity());
int len = buf.getInt(dataOffset);
buf.position(dataOffset + 4).limit(dataOffset + 4 + len);
return buf.slice();
}
}
/**
* Determines the length of the resource in bytes.
*/
public int getLength()
{
synchronized (buf)
{
return buf.getInt(dataOffset);
}
}
}
}

View file

@ -0,0 +1,686 @@
/* NameDecoder.java -- Decodes names of OpenType and TrueType fonts.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Locale;
/**
* A utility class that helps with decoding the names of OpenType
* and TrueType fonts.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
class NameDecoder
{
public static final int NAME_COPYRIGHT = 0;
/**
* Specifies the name of the family to which a font belongs, for
* example &#x201c;Univers&#x201d;.
*/
public static final int NAME_FAMILY = 1;
/**
* Specified the name of the font inside its family, for
* example &#x201c;Light&#x201d;.
*/
public static final int NAME_SUBFAMILY = 2;
public static final int NAME_UNIQUE = 3;
/**
* Specifies the full human-readable name of a font, for example
* &#x201c;Univers Light&#x201d;
*/
public static final int NAME_FULL = 4;
public static final int NAME_VERSION = 5;
/**
* Specifies the PostScript name of a font, for example
* &#x201c;Univers-Light&#x201d;.
*/
public static final int NAME_POSTSCRIPT = 6;
public static final int NAME_TRADEMARK = 7;
public static final int NAME_MANUFACTURER = 8;
public static final int NAME_DESIGNER = 9;
public static final int NAME_DESCRIPTION = 10;
public static final int NAME_VENDOR_URL = 11;
public static final int NAME_DESIGNER_URL = 12;
public static final int NAME_LICENSE = 13;
public static final int NAME_LICENSE_URL = 14;
public static final int NAME_PREFERRED_FAMILY = 16;
public static final int NAME_PREFERRED_SUBFAMILY = 17;
public static final int NAME_FULL_MACCOMPATIBLE = 18;
public static final int NAME_SAMPLE_TEXT = 19;
public static final int NAME_POSTSCRIPT_CID = 20;
private static final int PLATFORM_MACINTOSH = 1;
private static final int PLATFORM_MICROSOFT = 3;
public static String getName(ByteBuffer nameTable,
int name, Locale locale)
{
int numRecords;
int macLanguage, msLanguage;
int offset;
int namePlatform, nameEncoding, nameLanguage, nameID, nameLen;
int nameStart;
String result;
boolean match;
if (nameTable == null)
return null;
nameTable.position(0);
/* We understand only format 0 of the name table. */
if (nameTable.getChar() != 0)
return null;
macLanguage = getMacLanguageCode(locale);
msLanguage = getMicrosoftLanguageCode(locale);
numRecords = nameTable.getChar();
offset = nameTable.getChar();
for (int i = 0; i < numRecords; i++)
{
namePlatform = nameTable.getChar();
nameEncoding = nameTable.getChar();
nameLanguage = nameTable.getChar();
nameID = nameTable.getChar();
nameLen = nameTable.getChar();
nameStart = offset + nameTable.getChar();
if (nameID != name)
continue;
match = false;
switch (namePlatform)
{
case PLATFORM_MACINTOSH:
if ((nameLanguage == macLanguage) || (locale == null))
match = true;
else
{
switch (macLanguage)
{
case 49: /* Azerbaijani/Cyrillic */
match = (nameLanguage == /* Azerbaijani/Arabic */ 50)
|| (nameLanguage == /* Azerbaijani/Roman */ 150);
break;
case 57: /* Mongolian/Mongolian */
match = (nameLanguage == /* Mongolian/Cyrillic */ 58);
break;
case 83: /* Malay/Roman */
match = (nameLanguage == /* Malay/Arabic */ 84);
break;
}
}
break;
case PLATFORM_MICROSOFT:
if (((nameLanguage & 0xff) == msLanguage) || (locale == null))
match = true;
break;
}
if (match)
{
result = decodeName(namePlatform, nameEncoding, nameLanguage,
nameTable, nameStart, nameLen);
if (result != null)
return result;
}
}
return null;
}
/**
* The language codes used by the Macintosh operating system. MacOS
* defines numeric language identifiers in the range [0 .. 95] and
* [128 .. 150]. To map this numeric identifier into an ISO 639
* language code, multiply it by two and take the substring at that
* position.
*
* <p>ISO 639 has revised the code for some languages, namely
* <code>he</code> for Hebrew (formerly <code>iw</code>),
* <code>yi</code> (formerly <code>ji</code>), and <code>id</code>
* for Indonesian (formerly <code>in</code>). In those cases, this
* table intentionally contains the older, obsolete code. The
* reason is that this is the code which
* java.util.Locale.getLanguage() is specified to return. The
* implementation of {@link #getMacLanguageCode} depends on this.
*
* @see <a href=
* "http://www.unicode.org/unicode/onlinedat/languages.html"
* >Language Codes: ISO 639, Microsoft and Macintosh</a>
*/
private static final String macLanguageCodes
// 0 1 2
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
= "enfrdeitnlsvesdaptnoiwjaarfielismttrhrzhurhithkoltplhuetlv "
// 3 4 5
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "fofaruzhnlgdsqrocssksljisrmkbgukbeuzkkazazhykamokytgtkmnmnps"
// 6 7 8
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "kukssdbonesamrbnasgupaormlkntatesimykmloviintlmsmsamti sosw"
// 9 10 11
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "rwrn mgeo "
// 12 13 14
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ " cyeucalaqugnayttugtsjwsuglafbriugdgvgatoelkl"
// 15
// 0
+ "az";
/**
* The primary language IDs used by the Microsoft operating systems.
*
* <p>ISO 639 has revised the code for some languages, namely
* <code>he</code> for Hebrew (formerly <code>iw</code>),
* <code>yi</code> (formerly <code>ji</code>), and <code>id</code>
* for Indonesian (formerly <code>in</code>). In those cases, this
* table intentionally contains the older, obsolete code. The
* reason is that this is the code which
* java.util.Locale.getLanguage() is specified to return. The
* implementation of {@link #getMicrosoftLanguageCode} depends on
* this.
*
* @see <a href=
* "http://www.unicode.org/unicode/onlinedat/languages.html"
* >Language Codes: ISO 639, Microsoft and Macintosh</a>
*/
private static final String microsoftLanguageCodes
// 0 1 2
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
= " arbgcazhcsdadeelenesfifriwhuisitjakonlnoplptrmrorushsksqsv"
// 3 4 5
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "thtrurinukbesletlvlttgfavihyazeu mk ts xhzuafkafohimt "
// 6 7 8
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ "gajimskkkyswtkuzttbnpaguortateknmlasmrsamnbocykmlomygl sd"
// 9 10 11
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
+ " si iuam ksnefypstl ha yo omtign laso";
/**
* Maps a Java Locale into a MacOS language code.
*
* <p>For languages that are written in several script systems,
* MacOS defines multiple language codes. Java Locales have a
* variant which could be used for that purpose, but a small
* test program revealed that with Sun's JDK 1.4.1_01, only two
* of 134 available Locales have a variant tag (namely no_NO_NY
* and th_TH_TH).</p>
*
* <p>The following cases are problematic:
*
* <ul> <li>Azerbaijani (az): The MacOS language code is 49 if
* Azerbaijani is written in the Cyrillic script; 50 if written in
* the Arabic script; 150 if written in the Roman script. This
* method will always return 49 for the Azerbaijani locale.</li>
*
* <li>Mongolian (mn): The MacOS language code is 57 if Mongolian is
* written in the Mongolian script; 58 if written in the Cyrillic
* script. This method will always return 57 for the Mongolian
* locale.</li>
*
* <li>Malay (ms): The MacOS language code is 83 if Malay is written
* in the Roman script; 84 if written in the Arabic script. This
* method will always return 83 for the Malay locale.</li> </ul>
*
* @return a MacOS language code, or -1 if there is no such code for
* <code>loc</code>&#x2019;s language.
*/
private static int getMacLanguageCode(Locale loc)
{
int code;
if (loc == null)
return -1;
code = findLanguageCode(loc.getLanguage(), macLanguageCodes);
switch (code)
{
case 19:
/* Traditional Chinese (MacOS language #19) and and Simplified
* Chinese (MacOS language #33) both have "zh" as their ISO 639
* code.
*/
if (loc.equals(Locale.SIMPLIFIED_CHINESE))
code = 33;
break;
// Other special cases would be 49, 57 and 83, but we do not
// know what do do about them. See the method documentation for
// details.
}
return code;
}
/**
* Maps a Java Locale into a Microsoft language code.
*/
private static int getMicrosoftLanguageCode(Locale locale)
{
String isoCode;
int code;
if (locale == null)
return -1;
isoCode = locale.getLanguage();
code = findLanguageCode(isoCode, microsoftLanguageCodes);
if (code == -1)
{
if (isoCode.equals("hr") || isoCode.equals("sr"))
{
/* Microsoft uses code 26 for "sh" (Serbo-Croatian),
* "hr" (Croatian) and "sr" (Serbian). Our table contains
* "sh".
*/
code = 26;
}
else if (isoCode.equals("gd"))
{
/* Microsoft uses code 60 for "gd" (Scottish Gaelic) and
* "ga" (Irish Gaelic). Out table contains "ga".
*/
code = 60;
}
}
return code;
}
private static int findLanguageCode(String lang, String langCodes)
{
int index;
if (lang == null)
return -1;
if (lang.length() != 2)
return -1;
index = 0;
do
{
index = langCodes.indexOf(lang, index);
/* The index must be even to be considered a match. Otherwise, we
* could match with the second letter of one language and the
* first of antoher one.
*/
}
while (!((index < 0) || ((index & 1) == 0)));
if (index < 0)
return -1;
index = index / 2;
return index;
}
private static String decodeName(int platform, int encoding, int language,
ByteBuffer buffer, int offset, int len)
{
byte[] byteBuf;
String charsetName;
int oldPosition;
charsetName = getCharsetName(platform, language, encoding);
if (charsetName == null)
return null;
byteBuf = new byte[len];
oldPosition = buffer.position();
try
{
buffer.position(offset);
buffer.get(byteBuf);
try
{
return new String(byteBuf, charsetName);
}
catch (UnsupportedEncodingException uex)
{
}
}
finally
{
buffer.position(oldPosition);
}
return null;
}
/**
* Maps a MacOS language code into a Java Locale.
*
* @param macLanguageCode the MacOS language code for
* the language whose Java locale is to be retrieved.
*
* @return an suitable Locale, or <code>null</code> if
* the mapping cannot be performed.
*/
private static Locale getMacLocale(int macLanguageCode)
{
String isoCode;
switch (macLanguageCode)
{
case 0: return Locale.ENGLISH;
case 1: return Locale.FRENCH;
case 2: return Locale.GERMAN;
case 3: return Locale.ITALIAN;
case 11: return Locale.JAPANESE;
case 23: return Locale.KOREAN;
case 19: return Locale.TRADITIONAL_CHINESE;
case 33: return Locale.SIMPLIFIED_CHINESE;
}
if ((macLanguageCode < 0) || (macLanguageCode > 150))
return null;
isoCode = macLanguageCodes.substring(macLanguageCode << 1,
(macLanguageCode + 1) << 1);
if (isoCode.charAt(0) == ' ')
return null;
return new Locale(isoCode);
}
/**
* Maps a Windows LCID into a Java Locale.
*
* @param lcid the Windows language ID whose Java locale
* is to be retrieved.
*
* @return an suitable Locale, or <code>null</code> if
* the mapping cannot be performed.
*/
private static Locale getWindowsLocale(int lcid)
{
/* FIXME: This is grossly incomplete. */
switch (lcid)
{
case 0x0407: return Locale.GERMAN;
case 0x0408: return new Locale("el", "GR");
case 0x0409: return Locale.ENGLISH;
case 0x040b: return new Locale("fi");
case 0x040c: return Locale.FRENCH;
case 0x0416: return new Locale("pt");
case 0x0807: return new Locale("de", "CH");
case 0x0809: return new Locale("en", "UK");
case 0x080c: return new Locale("fr", "BE");
case 0x0816: return new Locale("pt", "BR");
case 0x0c07: return new Locale("de", "AT");
case 0x0c09: return new Locale("en", "AU");
case 0x0c0c: return new Locale("fr", "CA");
case 0x1007: return new Locale("de", "LU");
case 0x1009: return new Locale("en", "CA");
case 0x100c: return new Locale("fr", "CH");
case 0x1407: return new Locale("de", "LI");
case 0x1409: return new Locale("en", "NZ");
case 0x140c: return new Locale("fr", "LU");
case 0x1809: return new Locale("en", "IE");
default:
return null;
}
}
/**
* Maps a Macintosh Script Manager code to the name of the
* corresponding Java Charset.
*
* @param macScript a MacOS ScriptCode, for example
* 6 for <code>smGreek</code>.
*
* @return a String that can be used to retrieve a Java
* CharsetDecorder, for example <code>MacGreek</code>, or
* <code>null</code> if <code>macScript</code> has an
* unsupported value.
*/
private static String getMacCharsetName(int macScript)
{
switch (macScript)
{
case 0: return "MacRoman";
case 1: return "MacJapanese";
case 2: return "MacKorean";
case 3: return "MacTradChinese";
case 4: return "MacArabic";
case 5: return "MacHebrew";
case 6: return "MacGreek";
case 7: return "MacCyrillic";
case 8: return "MacRSymbol";
case 9: return "MacDevanagari";
case 10: return "MacGurmukhi";
case 11: return "MacGujarati";
case 12: return "MacOriya";
case 13: return "MacBengali";
case 14: return "MacTamil";
case 15: return "MacTelugu";
case 16: return "MacKannada";
case 17: return "MacMalayalam";
case 18: return "MacSinhalese";
case 19: return "MacBurmese";
case 20: return "MacKhmer";
case 21: return "MacThai";
case 22: return "MacLao";
case 23: return "MacGeorgian";
case 24: return "MacArmenian";
case 25: return "MacSimpChinese";
case 26: return "MacTibetan";
case 27: return "MacMongolian";
case 28: return "MacEthiopic";
case 29: return "MacCentralEurope";
case 30: return "MacVietnamese";
case 31: return "MacExtArabic";
default: return null;
}
}
/**
* Maps a Microsoft locale ID (LCID) to the name of the
* corresponding Java Charset.
*
* @param lcid the Microsoft locale ID.
*
* @return a String that can be used to retrieve a Java
* CharsetDecorder, for example <code>windows-1252</code>, or
* <code>null</code> if <code>lcid</code> has an unsupported value.
*/
private static String getMicrosoftCharsetName(int lcid)
{
int lang;
char codePage = '?';
/* Extract the language code from the LCID. */
lang = lcid & 0x3ff;
/* In the majority of cases, the language alone determines the
* codepage.
*/
if (lang < 100)
codePage = (" 612D022322225022EC2202201?002A462110777 68 ?2 1 "
+ " 2 2 2112 ?1 1 2 2 ")
.charAt(lang);
/* There are a few exceptions, however, where multiple code pages
* are used for the same language. */
if (codePage == '?')
{
switch (lcid)
{
case 0x041a: // Croatian --> Windows-1250 (Central Europe)
case 0x081a: // Serbian (Latin) --> Windows-1250 (Central Europe)
codePage = '0';
break;
case 0x42c: // Azeri (Latin) --> Windows-1254 (Turkish)
case 0x443: // Uzbek (Latin) --> Windows-1254 (Turkish)
codePage = '4';
break;
case 0x82c: // Azeri (Cyrillic) --> Windows-1251 (Cyrillic)
case 0x843: // Uzbek (Cyrillic) --> Windows-1251 (Cyrillic)
case 0xc1a: // Serbian (Cyrillic) --> Windows-1251 (Cyrillic)
codePage = '1';
break;
}
}
switch (codePage)
{
case '0': return "windows-1250"; // Central Europe
case '1': return "windows-1251"; // Cyrillic
case '2': return "windows-1252"; // Latin 1
case '3': return "windows-1253"; // Greek
case '4': return "windows-1254"; // Turkish
case '5': return "windows-1255"; // Hebrew
case '6': return "windows-1256"; // Arabic
case '7': return "windows-1257"; // Baltic
case '8': return "windows-1258"; // Vietnam
case 'A': return "windows-874"; // Thai
case 'B': return "windows-936"; // Simplified Chinese, GBK
case 'C': return "windows-949"; // Korean
case 'D': return "windows-950"; // Traditional Chinese, Big5
case 'E': return "windows-932"; // Japanese Shift-JIS
default: return null;
}
}
/**
* Returns the Locale of an OpenType name.
*
* @param platform the OpenType platform ID.
*
* @param language the language tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS language code.
*
* @param encoding the encoding tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS script code.
*/
public static Locale getLocale(int platform, int language, int encoding)
{
switch (platform)
{
case 1: /* Apple Macintosh */
return getMacLocale(language);
case 3: /* Microsoft Windows */
return getWindowsLocale(language);
default:
return null;
}
}
/**
* Determines the name of the charset for an OpenType font name.
*
* @param platform the OpenType platform ID.
*
* @param language the language tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS language code.
*
* @param encoding the encoding tag of the OpenType name. If
* <code>platform</code> is 1, this is the MacOS script code.
*
* @return a charset name such as <code>&quot;MacRoman&quot;</code>,
* or <code>null</code> if the combination is not known.
*/
public static String getCharsetName(int platform, int language, int encoding)
{
switch (platform)
{
case 1: /* Apple Macintosh */
return getMacCharsetName(encoding);
case 3: /* Microsoft Windows */
return getMicrosoftCharsetName(language);
default:
return null;
}
}
}

View file

@ -0,0 +1,825 @@
/* OpenTypeFont.java -- Manages OpenType and TrueType fonts.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.OpenType;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;
import java.text.CharacterIterator;
import java.util.Locale;
import gnu.java.awt.font.FontDelegate;
import gnu.java.awt.font.GNUGlyphVector;
import gnu.java.awt.font.opentype.truetype.TrueTypeScaler;
/**
* A font that takes its data from OpenType or TrueType font tables.
*
* <p>OpenType is an extension of the TrueType font format. In addition
* to tables for names, kerning or layout, it also stores the shapes
* of individual glyphs. Three formats are recognized for glyphs:
* Quadratic splines (classic TrueType), cubic splines (PostScript),
* and bitmaps.
*
* @see <a
* href="http://partners.adobe.com/asn/tech/type/opentype/">Adobe&#x2019;s
* OpenType specification</a>
*
* @see <a
* href="http://developer.apple.com/fonts/TTRefMan/">Apple&#x2019;s</code>
* TrueType specification</a>
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public final class OpenTypeFont
implements FontDelegate
{
static final int TAG_OTTO = 0x4f54544f; // 'OTTO'
static final int TAG_SFNT = 0x73666e74; // 'sfnt'
static final int TAG_TRUE = 0x74727565; // 'true'
static final int TAG_TTCF = 0x74746366; // 'ttcf'
static final int TAG_ZAPF = 0x5a617066; // 'Zapf'
/**
* A buffer containing the font data. Note that this may well be an
* instance of the subclass MappedByteBuffer, in which case the
* virtual memory subsystem can more efficiently handle requests for
* font data. This is especially recommended for large font files
* that contain many glyphs that are rarely accessed.
*/
ByteBuffer buf;
/**
* The number of glyphs in this font.
*/
final int numGlyphs;
int[] tableTag, tableStart, tableLength;
/**
* The version of the font in 16.16 fixed-point encoding, for
* example 0x00010000 for version 1.0. There are also two special
* version IDs used by fonts for Apple Macintosh, namely 'true'
* (0x74727565) and 'typ1'. OpenType fonts sometimes have 'OTTO' as
* their version.
*/
private int version;
/**
* The number of font units per em. For fonts with TrueType
* outlines, this is usually a power of two (such as 2048). For
* OpenType fonts with PostScript outlines, other values are
* acceptable (such as 1000).
*/
private int unitsPerEm;
/**
* A factor to convert font units into ems. This value is <code>1 /
* unitsPerEm</code>.
*/
private float emsPerUnit;
/**
* The scaler to which the actual scaling work is delegated.
*/
private Scaler scaler;
/**
* A delegate object for mapping Unicode UCS-4 codepoints to glyph
* IDs.
*/
private CharGlyphMap cmap;
/**
* A delegate object for providing a name for each glyph.
*/
private GlyphNamer glyphNamer;
/**
* Constructs an OpenType or TrueType font.
*
* @param buf a buffer with the contents of the font file. It is
* recommended to use a <code>MappedByteBuffer</code> for very
* large font files.
*
* @param offsetTablePosition the position of the OpenType offset
* table in the font file. The offset table of most OpenType and
* TrueType fonts starts at position 0. However, so-called TrueType
* Collections support multiple OpenType fonts in a single file,
* which allows sharing some glyphs between fonts. If many glyphs
* are shared (for example all the Kanji glyphs between multiple
* Japanese fonts), the space savings can be considerable. In that
* case, the offset table of each individual font would start at its
* own position.
*
* @throws java.awt.FontFormatException if the font data is
* not in OpenType or TrueType format.
*/
OpenTypeFont(ByteBuffer buf, int offsetTablePosition)
throws FontFormatException
{
int numTables, searchRange, entrySelector, rangeShift;
//buf = buf.duplicate();
this.buf = buf;
buf.limit(buf.capacity());
buf.position(offsetTablePosition);
/* Check that the font data is in a supported format. */
version = buf.getInt();
switch (version)
{
case 0x00010000: // Microsoft TrueType
case OpenType.TAG_TYP1: // Adobe PostScript embeded in Apple SFNT ('typ1')
case TAG_SFNT: // Apple TrueType
case TAG_TRUE: // Apple TrueType
case TAG_OTTO: // OpenType
break;
default:
throw new FontFormatException("not in OpenType or TrueType format");
}
numTables = buf.getShort();
searchRange = buf.getShort();
entrySelector = buf.getShort();
rangeShift = buf.getShort();
tableTag = new int[numTables];
tableStart = new int[numTables];
tableLength = new int[numTables];
int lastTag = 0;
for (int i = 0; i < numTables; i++)
{
tableTag[i] = buf.getInt();
if (lastTag >= tableTag[i])
throw new FontFormatException("unordered OpenType table");
buf.getInt(); // ignore checksum
tableStart[i] = buf.getInt();
tableLength[i] = buf.getInt();
//System.out.println(tagToString(tableTag[i]) + ", " + tableLength[i]);
}
ByteBuffer head = getFontTable(OpenType.TAG_HEAD);
if ((head.getInt(0) != 0x00010000)
|| (head.getInt(12) != 0x5f0f3cf5))
throw new FontFormatException("unsupported head version");
unitsPerEm = head.getChar(18);
emsPerUnit = 1.0f / (float) unitsPerEm;
ByteBuffer maxp = getFontTable(OpenType.TAG_MAXP);
int maxpVersion = maxp.getInt(0);
switch (maxpVersion)
{
case 0x00005000: /* version 0.5, with wrong fractional part */
numGlyphs = maxp.getChar(4);
break;
case 0x00010000: /* version 1.0 */
numGlyphs = maxp.getChar(4);
scaler = new TrueTypeScaler(unitsPerEm,
getFontTable(OpenType.TAG_HHEA),
getFontTable(OpenType.TAG_HMTX),
getFontTable(OpenType.TAG_VHEA),
getFontTable(OpenType.TAG_VMTX),
maxp,
getFontTable(OpenType.TAG_CVT),
getFontTable(OpenType.TAG_FPGM),
/* loca format */ head.getShort(50),
getFontTable(OpenType.TAG_LOCA),
getFontTable(OpenType.TAG_GLYF),
getFontTable(OpenType.TAG_PREP));
break;
default:
throw new FontFormatException("unsupported maxp version");
}
}
/**
* Determines the index of a table into the offset table. The
* result can be used to find the offset and length of a table, as
* in <code>tableStart[getTableIndex(TAG_NAME)]</code>.
*
* @param tag the table identifier, for instance
* <code>OpenType.TAG_NAME</code>.
*
* @return the index of that table into the offset table, or
* -1 if the font does not contain the table specified by
* <code>tag</code>.
*/
private int getTableIndex(int tag)
{
/* FIXME: Since the font specification requires tableTag[] to be
* ordered, one should do binary search here.
*/
for (int i = 0; i < tableTag.length; i++)
if (tableTag[i] == tag)
return i;
return -1;
}
/**
* Returns the name of the family to which this font face belongs,
* for example <i>&#x201c;Univers&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the family name.
*/
public synchronized String getFamilyName(Locale locale)
{
String name;
if (locale == null)
locale = Locale.getDefault();
name = getName(NameDecoder.NAME_FAMILY, locale);
if (name == null)
name = getName(NameDecoder.NAME_FAMILY, Locale.ENGLISH);
if (name == null)
name = getName(NameDecoder.NAME_FAMILY, /* any language */ null);
if (name == null)
name = getName(NameDecoder.NAME_FULL, locale);
if (name == null)
name = getName(NameDecoder.NAME_FULL, /* any language */ null);
return name;
}
/**
* Returns the name of this font face inside the family, for example
* <i>&#x201c;Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the name of the face inside its family.
*/
public synchronized String getSubFamilyName(Locale locale)
{
String name;
if (locale == null)
locale = Locale.getDefault();
name = getName(NameDecoder.NAME_SUBFAMILY, locale);
if (name == null)
{
name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH);
if ("Regular".equals(name))
name = null;
}
if (name == null)
{
String lang = locale.getLanguage();
if ("de".equals(lang))
name = "Standard";
else if ("fr".equals(lang))
name = "Standard";
else if ("it".equals(lang))
name = "Normale";
else if ("nl".equals(lang))
name = "Normaal";
else if ("fi".equals(lang))
name = "Normaali";
else if ("sv".equals(lang))
name = "Normal";
else
name = "Regular";
}
return name;
}
/**
* Returns the full name of this font face, for example
* <i>&#x201c;Univers Light&#x201d;</i>.
*
* @param locale the locale for which to localize the name.
*
* @return the face name.
*/
public synchronized String getFullName(Locale locale)
{
String name;
if (locale == null)
locale = Locale.getDefault();
name = getName(NameDecoder.NAME_FULL, locale);
if (name == null)
name = getName(NameDecoder.NAME_FULL, Locale.ENGLISH);
if (name == null)
name = getName(NameDecoder.NAME_FULL, /* any language */ null);
return name;
}
/**
* Returns the PostScript name of this font face, for example
* <i>&#x201c;Univers-Light&#x201d;</i>.
*
* @return the PostScript name, or <code>null</code> if the font
* does not provide a PostScript name.
*/
public synchronized String getPostScriptName()
{
return getName(NameDecoder.NAME_POSTSCRIPT, /* any language */ null);
}
/**
* Returns the number of glyphs in this font face.
*/
public int getNumGlyphs()
{
/* No synchronization is needed because the number of glyphs is
* set in the constructor, and it cannot change during the
* lifetime of the object.
*/
return numGlyphs;
}
/**
* Returns the index of the glyph which gets displayed if the font
* cannot map a Unicode code point to a glyph. Many fonts show this
* glyph as an empty box.
*/
public int getMissingGlyphCode()
{
/* No synchronization is needed because the result is constant. */
return 0;
}
/**
* The font&#x2019;s name table, or <code>null</code> if this
* table has not yet been accessed.
*/
private ByteBuffer nameTable;
/**
* Extracts a String from the font&#x2019;s name table.
*
* @param name the numeric TrueType or OpenType name ID.
*
* @param locale the locale for which names shall be localized, or
* <code>null</code> if the locale does mot matter because the name
* is known to be language-independent (for example, because it is
* the PostScript name).
*/
private String getName(int name, Locale locale)
{
if (nameTable == null)
nameTable = getFontTable(OpenType.TAG_NAME);
return NameDecoder.getName(nameTable, name, locale);
}
/**
* Returns the version of the font.
*
* @see java.awt.font.OpenType#getVersion
*
* @return the version in 16.16 fixed-point encoding, for example
* 0x00010000 for version 1.0.
*/
public int getVersion()
{
/* No synchronization is needed because the version is set in the
* constructor, and it cannot change during the lifetime of the
* object.
*/
return version;
}
/**
* Creates a view buffer for an OpenType table. The caller can
* access the returned buffer without needing to synchronize access
* from multiple threads.
*
* @param tag the table identifier, for example
* <code>OpenType.GLYF</code>.
*
* @return a slice of the underlying buffer containing the table, or
* <code>null</code> if the font does not contain the requested
* table.
*/
public synchronized ByteBuffer getFontTable(int tag)
{
int index, start, len;
ByteBuffer result;
index = getTableIndex(tag);
if (index < 0)
return null;
start = tableStart[index];
len = tableLength[index];
buf.limit(start + len).position(start);
result = buf.slice();
result.limit(len);
return result;
}
/**
* Returns the size of one of the tables in the font,
* or -1 if the table does not exist.
*/
public int getFontTableSize(int tag)
{
int index = getTableIndex(tag);
if (index == -1)
return index;
return tableLength[index];
}
private CharGlyphMap getCharGlyphMap()
{
if (cmap != null)
return cmap;
synchronized (this)
{
if (cmap == null)
{
int index = getTableIndex(OpenType.TAG_CMAP);
int start = tableStart[index];
buf.limit(start + tableLength[index]).position(start);
cmap = CharGlyphMap.forTable(buf);
}
return cmap;
}
}
/**
* Looks up a glyph in the font&#x2019;s <code>cmap</code> tables,
* without performing any glyph substitution or reordering. Because
* of this limitation, this method cannot be used for script systems
* that need advanced glyph mapping, such as Arabic, Korean, or even
* Latin with exotic accents.
*
* <p>It is safe to call this method from any thread.
*
* @param ucs4 the Unicode codepoint in the 32-bit Unicode character
* set UCS-4. Because UTF-16 surrogates do not correspond to a single
* glyph, it does not make sense to pass them here.
*
* @return the glyph index, or zero if the font does not contain
* a glyph for the specified codepoint.
*/
public int getGlyph(int ucs4)
{
return getCharGlyphMap().getGlyph(ucs4);
}
/**
* Creates a GlyphVector by mapping each character in a
* CharacterIterator to the corresponding glyph.
*
* <p>The mapping takes only the font&#x2019;s <code>cmap</code>
* tables into consideration. No other operations (such as glyph
* re-ordering, composition, or ligature substitution) are
* performed. This means that the resulting GlyphVector will not be
* correct for text in languages that have complex
* character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or
* Thai.
*
* @param font the font object that the created GlyphVector
* will return when it gets asked for its font. This argument is
* needed because the public API works with java.awt.Font,
* not with some private delegate like OpenTypeFont.
*
* @param frc the font rendering parameters that are used for
* measuring glyphs. The exact placement of text slightly depends on
* device-specific characteristics, for instance the device
* resolution or anti-aliasing. For this reason, any measurements
* will only be accurate if the passed
* <code>FontRenderContext</code> correctly reflects the relevant
* parameters. Hence, <code>frc</code> should be obtained from the
* same <code>Graphics2D</code> that will be used for drawing, and
* any rendering hints should be set to the desired values before
* obtaining <code>frc</code>.
*
* @param ci a CharacterIterator for iterating over the
* characters to be displayed.
*/
public synchronized GlyphVector createGlyphVector(Font font,
FontRenderContext frc,
CharacterIterator ci)
{
CharGlyphMap cmap;
int numGlyphs;
int[] glyphs;
int glyph;
int c;
cmap = getCharGlyphMap();
numGlyphs = ci.getEndIndex() - ci.getBeginIndex();
glyphs = new int[numGlyphs];
glyph = 0;
for (c = ci.first(); c != CharacterIterator.DONE; c = ci.next())
{
/* handle surrogate pairs */
if (c >> 10 == 0x36) // U+D800 .. U+DBFF: High surrogate
c = (((c & 0x3ff) << 10) | (ci.next() & 0x3ff)) + 0x10000;
glyphs[glyph] = cmap.getGlyph(c);
glyph += 1;
}
/* If we had surrogates, the allocated array is too large.
* Because this will occur very rarely, it seems acceptable to
* re-allocate a shorter array and copy the contents around.
*/
if (glyph != numGlyphs)
{
int[] newGlyphs = new int[glyph];
System.arraycopy(glyphs, 0, newGlyphs, 0, glyph);
glyphs = newGlyphs;
}
return new GNUGlyphVector(this, font, frc, glyphs);
}
/**
* Determines the advance width for a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is possible
* that both values are non-zero, for example if
* <code>transform</code> is a rotation, or in the case of Urdu
* fonts.
*/
public synchronized void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance)
{
/* Delegate the measurement to the scaler. The synchronization is
* needed because the scaler is not synchronized.
*/
scaler.getAdvance(glyphIndex, pointSize, transform,
antialias, fractionalMetrics, horizontal,
advance);
}
/**
* Returns the shape of a glyph.
*
* @param glyph the glyph whose advance width is to be determined
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts, this
* parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional
* metrics, <code>false</code> for rounding the result to a pixel
* boundary.
*
* @return the scaled and grid-fitted outline of the specified
* glyph, or <code>null</code> for bitmap fonts.
*/
public synchronized GeneralPath getGlyphOutline(int glyph,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics)
{
/* The synchronization is needed because the scaler is not
* synchronized.
*/
return scaler.getOutline(glyph, pointSize, transform,
antialias, fractionalMetrics);
}
/**
* Returns a name for the specified glyph. This is useful for
* generating PostScript or PDF files that embed some glyphs of a
* font.
*
* <p><b>Names are not unique:</b> Under some rare circumstances,
* the same name can be returned for different glyphs. It is
* therefore recommended that printer drivers check whether the same
* name has already been returned for antoher glyph, and make the
* name unique by adding the string ".alt" followed by the glyph
* index.</p>
*
* <p>This situation would occur for an OpenType or TrueType font
* that has a <code>post</code> table of format 3 and provides a
* mapping from glyph IDs to Unicode sequences through a
* <code>Zapf</code> table. If the same sequence of Unicode
* codepoints leads to different glyphs (depending on contextual
* position, for example, or on typographic sophistication level),
* the same name would get synthesized for those glyphs.
*
* @param glyphIndex the glyph whose name the caller wants to
* retrieve.
*/
public synchronized String getGlyphName(int glyphIndex)
{
if (glyphNamer == null)
glyphNamer = GlyphNamer.forTables(numGlyphs,
getFontTable(OpenType.TAG_POST),
getFontTable(TAG_ZAPF));
return glyphNamer.getGlyphName(glyphIndex);
}
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public synchronized float getAscent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal)
{
return scaler.getAscent(pointSize, transform,
antialiased, fractionalMetrics,
horizontal);
}
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public synchronized float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal)
{
return scaler.getDescent(pointSize, transform,
antialiased, fractionalMetrics,
horizontal);
}
/**
* Converts a four-byte tag identifier into a String that can be
* displayed when debugging this class.
*
* @param tag the tag as an <code>int</code>.
*
* @return the tag in human-readable form, for example
* <code>name</code> or <code>glyf</code>.
*/
static String tagToString(int tag)
{
char[] c = new char[4];
c[0] = (char) ((tag >> 24) & 0xff);
c[1] = (char) ((tag >> 16) & 0xff);
c[2] = (char) ((tag >> 8) & 0xff);
c[3] = (char) (tag & 0xff);
return new String(c);
}
}

View file

@ -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");
}
}

View file

@ -0,0 +1,192 @@
/* Scaler.java -- Common superclass for font scalers.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
/**
* An common superclass for all font scalers. The main task of font
* scaler is to retrieve a scaled and hinted outline for a glyph.
*
* <p>To make text more legible, high-quality fonts contain
* instructions (sometimes also called &#x201c;hints&#x201d;) for
* moving the scaled control points towards the coordinate grid of the
* display device.
*
* <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
* <i>not</i> safe to access from multiple concurrent
* threads. Synchronization needs to be performed externally. Usually,
* the font that uses this scaler already has obtained a lock before
* calling the scaler.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public abstract class Scaler
{
/**
* Retrieves the scaled outline of a glyph, adjusting control points
* to the raster grid if necessary.
*
* @param glyph the glyph number whose outline is retrieved.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias whether or not the rasterizer will perform
* anti-aliasing on the returned path.
*
* @param fractionalMetrics <code>false</code> for adjusting glyph
* positions to the raster grid of device space.
*
* @return the scaled and grid-fitted outline of the specified
* glyph, or <code>null</code> for bitmap fonts.
*/
public abstract GeneralPath getOutline(int glyph,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics);
/**
* Determines the advance width and height for a glyph.
*
* @param glyphIndex the glyph whose advance width is to be
* determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is well
* possible that both values are non-zero, for example for rotated
* text or for Urdu fonts.
*/
public abstract void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance);
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public abstract float getAscent(float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal);
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public abstract float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal);
}

View file

@ -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();
}
}

View file

@ -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));
}
}

View file

@ -0,0 +1,187 @@
/* GlyphLocator.java -- Locates outlines of TrueType glyphs.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype.truetype;
import java.awt.FontFormatException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
/**
* Locates glyph outlines in a TrueType or OpenType <code>glyf</code>
* table.
*
* @see <a href=
* "http://partners.adobe.com/asn/tech/type/opentype/loca.html"
* >Adobe&#x2019;s specification of the OpenType &#x2018;loca&#x2019;
* table</a>
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
abstract class GlyphLocator
{
/**
* The actual glyph data of the font, which is contained in the
* 'glyf' table.
*/
protected ByteBuffer glyfTable;
/**
* Creates a new GlyphLocator for a <code>loca</code> table.
*
* @param format the format of the <code>loca</code> table. The
* value must be 0 for two-byte offsets, or 1 for four-byte
* offsets. TrueType and OpenType fonts indicate the format in the
* <code>indexToLoc</code> field of the <a href=
* "http://partners.adobe.com/asn/tech/type/opentype/head.html"
* >font header</a>.
*
* @param loca the <code>loca</code> table of the font, which
* contains the position of each glyph in the <code>glyf</code>
* table.
*
* @param glyf the <code>glyf</code> table of the font, which
* contains the outline data of each glyph.
*
* @throws FontFormatException if <code>format</code> is neither 0
* nor 1.
*/
public static GlyphLocator forTable(int format, ByteBuffer loca,
ByteBuffer glyf)
throws FontFormatException
{
switch (format)
{
case 0:
return new GlyphLocator.TwoByte(loca, glyf);
case 1:
return new GlyphLocator.FourByte(loca, glyf);
default:
throw new FontFormatException("unsupported loca format");
}
}
/**
* Locates the outline data for a glyph.
*
* <p>For efficiency, the glyph locator does not create a new buffer
* for each invocation. Instead, this method always returns the same
* buffer object. Therefore, the data of a glyph must have been read
* completely before another glyph of the same font gets requested
* through this method.
*
* @param glyph the number of the glyph whose outlines are to be
* retrieved.
*
* @return a buffer whose position is set to the first byte of glyph
* data, and whose limit is set to disallow accessing any data that
* does not belong to the glyph. If there is no outline data for the
* requested glyph, as would be the case for the space glyph, the
* result will be <code>null</code>.
*/
public abstract ByteBuffer getGlyphData(int glyph);
/**
* A GlyphLocator that locates glyphs using two-byte offsets,
* interpreting <code>loca</code> tables of format 0.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
private final static class TwoByte
extends GlyphLocator
{
final CharBuffer indexToLoc;
TwoByte(ByteBuffer loca, ByteBuffer glyf)
{
this.glyfTable = glyf;
indexToLoc = loca.asCharBuffer();
}
public ByteBuffer getGlyphData(int glyph)
{
int offset, limit;
offset = ((int) indexToLoc.get(glyph)) << 1;
limit = ((int) indexToLoc.get(glyph + 1)) << 1;
if (offset >= limit)
return null;
glyfTable.limit(limit).position(offset);
return glyfTable;
}
}
/**
* A GlyphLocator that locates glyphs using four-byte offsets,
* interpreting <code>loca</code> tables of format 1.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
private final static class FourByte
extends GlyphLocator
{
final IntBuffer indexToLoc;
FourByte(ByteBuffer loca, ByteBuffer glyf)
{
this.glyfTable = glyf;
indexToLoc = loca.asIntBuffer();
}
public ByteBuffer getGlyphData(int glyph)
{
int offset, limit;
offset = indexToLoc.get(glyph);
limit = indexToLoc.get(glyph + 1);
if (offset >= limit)
return null;
glyfTable.limit(limit).position(offset);
return glyfTable;
}
}
}

View file

@ -0,0 +1,228 @@
/* GlyphMeasurer.java -- Helper for measuring TrueType glyphs.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype.truetype;
import java.awt.FontFormatException;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
/**
* A class for measuring TrueType and OpenType glyphs.
*
* <p><b>Lack of Thread Safety:</b> Glyph measurers are intentionally
* <i>not</i> safe to access from multiple concurrent
* threads. Synchronization needs to be performed externally. Usually,
* the font has already obtained a lock before calling the scaler,
* which in turn calls the GlyphMeasurer. It would thus be wasteful to
* acquire additional locks for the GlyphMeasurer.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class GlyphMeasurer
{
/**
* A view buffer that allows accessing the contents of the
* font&#x2019;s <code>hmtx</code> table as shorts.
*/
private final ShortBuffer horizontalGlyphMetrics;
/**
* A view buffer that allows accessing the contents of the
* font&#x2019;s <code>vmtx</code> table as shorts.
*/
private final ShortBuffer verticalGlyphMetrics;
private final int numLongHorizontalMetricsEntries;
private final int numLongVerticalMetricsEntries;
private final int horizontalAscent;
private final int verticalAscent;
private final int horizontalDescent;
private final int verticalDescent;
private final int horizontalLineGap;
/**
* Constructs a GlyphMeasurer from TrueType/OpenType font tables.
*
* @param hhea the <code>hhea</code> table, which contains
* information about horizontal metrics that is common to all
* glyphs.
*
* @param hmtx the <code>hmtx</code> table, which contains
* glyph-specific information about horizontal metrics.
*
* @param vhea the <code>vhea</code> table, which contains
* information about vertical metrics that is common to all
* glyphs. If a font does not provide such a table, pass
* <code>null</code>.
*
* @param vmtx the <code>vmtx</code> table, which contains
* glyph-specific information about vertical metrics. If a font
* does not provide such a table, pass <code>null</code>.
*/
GlyphMeasurer(ByteBuffer hhea, ByteBuffer hmtx,
ByteBuffer vhea, ByteBuffer vmtx)
throws FontFormatException
{
if ((hhea.getInt(0) != 0x00010000) || (hhea.getInt(30) != 0))
throw new FontFormatException("unsupported hhea format");
horizontalAscent = hhea.getShort(4);
horizontalDescent = hhea.getShort(6);
horizontalLineGap = hhea.getShort(8);
numLongHorizontalMetricsEntries = hhea.getChar(34);
horizontalGlyphMetrics = hmtx.asShortBuffer();
if (vhea != null)
{
verticalAscent = vhea.getShort(4);
verticalDescent = vhea.getShort(6);
numLongVerticalMetricsEntries = vhea.getChar(34);
verticalGlyphMetrics = vmtx.asShortBuffer();
}
else
{
verticalAscent = /* advanceWidthMax */ hhea.getChar(10) / 2;
verticalDescent = -verticalAscent;
numLongVerticalMetricsEntries = 0;
verticalGlyphMetrics = null;
}
}
/**
* Returns the distance from the baseline to the highest ascender.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the maximal ascent, in font units.
*/
public int getAscent(boolean horizontal)
{
return horizontal ? horizontalAscent : verticalAscent;
}
/**
* Returns the distance from the baseline to the lowest descender.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the maximal descent, in font units.
*/
public int getDescent(boolean horizontal)
{
return horizontal ? horizontalDescent : verticalDescent;
}
/**
* Returns the typographic line gap.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the line gap, in font units.
*/
public int getLineGap(boolean horizontal)
{
return horizontalLineGap;
}
/**
* Determines the advance width of a glyph, without considering
* hinting.
*
* @param glyphIndex the index of the glyph whose advance width is
* to be determined.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the advance width, in font units.
*/
public int getAdvanceWidth(int glyphIndex, boolean horizontal)
{
if (!horizontal)
return 0;
glyphIndex = Math.min(glyphIndex,
numLongHorizontalMetricsEntries - 1);
return horizontalGlyphMetrics.get(glyphIndex << 1);
}
/**
* Determines the advance width of a glyph, without considering
* hinting.
*
* @param glyphIndex the index of the glyph whose advance width is
* to be determined.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the advance width, in font units.
*/
public int getAdvanceHeight(int glyphIndex, boolean horizontal)
{
if (horizontal)
return 0;
/* If a font does not provide vertical glyph metrics, advance
* by the height of one horizontal line.
*/
if (verticalGlyphMetrics == null)
return horizontalAscent - horizontalDescent + horizontalLineGap;
glyphIndex = Math.min(glyphIndex,
numLongVerticalMetricsEntries - 1);
return verticalGlyphMetrics.get(glyphIndex << 1);
}
}

View file

@ -0,0 +1,372 @@
/* TrueTypeScaler.java -- Font scaler for TrueType outlines.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype.truetype;
import gnu.java.awt.font.opentype.Scaler;
import java.awt.FontFormatException;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.nio.ByteBuffer;
/**
* A scaler for fonts whose outlines are described in the TrueType
* format.
*
* <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
* <i>not</i> safe to access from multiple concurrent threads.
* Synchronization needs to be performed externally. Usually, the font
* that uses this scaler already has obtained a lock before calling
* the scaler.
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
public final class TrueTypeScaler
extends Scaler
{
/**
* The TrueType or OpenType table that contains the glyph outlines.
*/
private ByteBuffer glyfTable;
/**
* A helper object for loading glyph outlines.
*/
private GlyphLoader glyphLoader;
/**
* A helper object for measuring the advance width and height of a
* glyph.
*/
private final GlyphMeasurer glyphMeasurer;
private final Zone glyphZone;
/**
* The number of units per em. A typical value is 2048, but some
* font use other numbers as well.
*/
private int unitsPerEm;
/**
* Constructs a new TrueTypeScaler.
*
* @param unitsPerEm the number of font units per em. This value can
* be retrieved from the font&#x2019;s <code>head</code> table.
*
* @param maxp the <code>maxp</code> table of the font, which
* contains various constants needed for setting up the virtual
* machine that interprets TrueType bytecodes.
*
* @param controlValueTable the <code>cvt</code> table of the font,
* which contains the initial values of the control value table.
*
* @param fpgm the <code>fpgm</code> table of the font, which
* contains a font program that is executed exactly once. The
* purpose of the font program is to define functions and to patch
* the interpreter.
*
* @param locaFormat the format of the <code>loca</code> table. The
* value must be 0 for two-byte offsets, or 1 for four-byte
* offsets. TrueType and OpenType fonts indicate the format in the
* <code>indexToLoc</code> field of the <a href=
* "http://partners.adobe.com/asn/tech/type/opentype/head.html"
* >font header</a>.
*
* @param loca the <code>loca</code> table of the font, which
* contains for each glyph the offset of its outline data
* in <code>glyf</code>.
*
* @param glyf the <code>glyf</code> table of the font, which
* contains the outline data for all glyphs in the font.
*
* @param preProgram the <code>prep</code> table of the font, which
* contains a program that is executed whenever the point size or
* the device transform have changed. This program is called
* pre-program because it gets executed before the instructions of
* the individual glyphs. If the font does not contain a
* pre-program, pass <code>null</code>.
*
* @throws FontFormatException if <code>format</code> is neither 0
* nor 1.
*/
public TrueTypeScaler(int unitsPerEm,
ByteBuffer hhea,
ByteBuffer htmx,
ByteBuffer vhea,
ByteBuffer vtmx,
ByteBuffer maxp,
ByteBuffer controlValueTable,
ByteBuffer fpgm,
int locaFormat, ByteBuffer loca,
ByteBuffer glyf,
ByteBuffer preProgram)
throws FontFormatException
{
int maxContours, maxPoints;
VirtualMachine vm;
maxContours = Math.max(/* maxContours */ (int) maxp.getChar(8),
/* maxCompositeContours */ (int) maxp.getChar(12))
+ /* fix for some broken fonts */ 8;
maxPoints = Math.max(/* maxPoints */ (int) maxp.getChar(6),
/* maxCompositePoints */ (int) maxp.getChar(10))
+ /* fix for some broken fonts */ 12;
glyphZone = new Zone(maxPoints + /* four phantom points */ 4);
this.glyfTable = glyf;
vm = new VirtualMachine(unitsPerEm, maxp,
controlValueTable, fpgm,
preProgram);
GlyphLocator locator = GlyphLocator.forTable(locaFormat, loca, glyf);
glyphMeasurer = new GlyphMeasurer(hhea, htmx, vhea, vtmx);
glyphLoader = new GlyphLoader(locator, vm, unitsPerEm,
maxContours, maxPoints,
glyphMeasurer);
this.unitsPerEm = unitsPerEm;
}
/**
* Retrieves the scaled outline of a glyph, adjusting control points
* to the raster grid if necessary.
*
* @param glyphIndex the glyph number whose outline is retrieved.
*
* @param pointSize the point size for the glyph.
*
* @param deviceTransform an affine transformation for the device.
*
* @param antialias whether or not the rasterizer will perform
* anti-aliasing on the returned path.
*
* @param fractionalMetrics <code>false</code> for adjusting glyph
* positions to the raster grid of device space.
*/
public GeneralPath getOutline(int glyphIndex,
float pointSize,
AffineTransform deviceTransform,
boolean antialias,
boolean fractionalMetrics)
{
glyphLoader.loadGlyph(glyphIndex, pointSize, deviceTransform,
antialias, glyphZone);
return glyphZone.getPath();
}
/**
* Determines the advance width and height for a glyph.
*
* @param glyphIndex the glyph whose advance width and height is to
* be determined.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @param advance a point whose <code>x</code> and <code>y</code>
* fields will hold the advance in each direction. It is possible
* that both values are non-zero, for example if
* <code>transform</code> is a rotation, or in the case of Urdu
* fonts.
*/
public void getAdvance(int glyphIndex,
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal,
Point2D advance)
{
double x, y;
double scaleFactor = (double) pointSize / unitsPerEm;
/* FIXME: Should grid-fit if needed. Also, use cache if present
* in the font.
*/
advance.setLocation(
scaleFactor * glyphMeasurer.getAdvanceWidth(glyphIndex, horizontal),
scaleFactor * glyphMeasurer.getAdvanceHeight(glyphIndex, horizontal));
transform.transform(advance, advance);
}
/**
* Scales a value from font units to pixels, given the point size
* and the transform.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution.
*
* @param fractionalMetrics <code>true</code> for fractional
* metrics, <code>false</code> for rounding the result to a pixel
* boundary.
*
* @param horizontal <code>true</code> if the <code>funits</code>
* value is along the x axis, <code>false</code> if it is along the
* y axis.
*/
private float scaleFromFUnits(int funits,
float pointSize,
AffineTransform transform,
boolean fractionalMetrics,
boolean horizontal)
{
double s;
s = (double) pointSize / unitsPerEm;
if (transform != null)
s *= horizontal ? transform.getScaleY() : transform.getScaleX();
s *= funits;
if (!fractionalMetrics)
s = Math.round(s);
return (float) s;
}
/**
* Determines the distance between the base line and the highest
* ascender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialias <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the ascent, which usually is a positive number.
*/
public float getAscent(float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics,
boolean horizontal)
{
/* Note that the ascent is orthogonal to the direction of line
* layout: If the line direction is horizontal, the measurement of
* ascent is along the vertical axis, and vice versa.
*/
return scaleFromFUnits(glyphMeasurer.getAscent(horizontal),
pointSize,
transform,
fractionalMetrics,
/* reverse */ !horizontal);
}
/**
* Determines the distance between the base line and the lowest
* descender.
*
* @param pointSize the point size of the font.
*
* @param transform a transform that is applied in addition to
* scaling to the specified point size. This is often used for
* scaling according to the device resolution. Those who lack any
* aesthetic sense may also use the transform to slant or stretch
* glyphs.
*
* @param antialiased <code>true</code> for anti-aliased rendering,
* <code>false</code> for normal rendering. For hinted fonts,
* this parameter may indeed affect the result.
*
* @param fractionalMetrics <code>true</code> for fractional metrics,
* <code>false</code> for rounding the result to a pixel boundary.
*
* @param horizontal <code>true</code> for horizontal line layout,
* <code>false</code> for vertical line layout.
*
* @return the descent, which usually is a nagative number.
*/
public float getDescent(float pointSize,
AffineTransform transform,
boolean antialiased,
boolean fractionalMetrics,
boolean horizontal)
{
/* Note that the descent is orthogonal to the direction of line
* layout: If the line direction is horizontal, the measurement of
* descent is along the vertical axis, and vice versa.
*/
return scaleFromFUnits(glyphMeasurer.getDescent(horizontal),
pointSize,
transform,
fractionalMetrics,
/* reverse */ !horizontal);
}
}

File diff suppressed because it is too large Load diff

View file

@ -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;
}
}

View file

@ -0,0 +1,391 @@
/* ZonePathIterator.java -- A PathIterator over glyph zones.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.font.opentype.truetype;
import java.awt.geom.PathIterator;
/**
* A PathIterator that enumerates the non-phantom points in a zone.
*
* <p><b>Lack of thread safety:</b> Instances of this class are
* <i>not</i> safe to access from multiple concurrent threads.
*
* @see Zone
*
* @author Sascha Brawer (brawer@dandelis.ch)
*/
final class ZonePathIterator
implements PathIterator
{
/**
* If <code>state</code> has this value, <code>currentSegment</code>
* will emit a <code>SEG_LINETO</code> or <code>SEG_QUADTO</code> segment
* to the current point. For a discussion of subtleties of on-curve
* and off-curve points, please refer to the documentation for
* {@link #getSegment}.
*/
private static final int EMIT_SEGMENT = 0;
/**
* If <code>state</code> has this value, <code>currentSegment</code>
* will emit a <code>SEG_CLOSE</code> in order to close the sub-path
* for the current contour.
*/
private static final int EMIT_CLOSE = 1;
/**
* If <code>state</code> has this value, <code>currentSegment</code>
* will emit a <code>SEG_MOVETO</code> segment to the first point in
* the current contour. If the first point is off-curve, a suitable
* on-curve point is calculated.
*
* @see #getStartSegment
*/
private static final int EMIT_MOVETO = 2;
/**
* The state of the iterator, which is one of
* <code>EMIT_SEGMENT</code>, <code>EMIT_CLOSE</code>, or
* <code>EMIT_MOVETO</code>.
*/
private int state;
/**
* The zone whose segments are enumerated by this iterator.
*/
private Zone zone;
/**
* The total number of points in the zone, not including the four
* phantom points at its end.
*/
private int numPoints;
/**
* The number of the current point.
*/
private int curPoint;
/**
* The number of the first point in the current contour.
*/
private int contourStart;
/**
* Constructs a ZonePathIterator for the specified zone.
*
* @param zone the zone whose segments will be enumerated
* by this iterator.
*/
ZonePathIterator(Zone zone)
{
this.zone = zone;
numPoints = zone.getSize() - /* four phantom points */ 4;
// The first segment that needs to be emitted is a SEG_MOVETO.
state = EMIT_MOVETO;
}
/**
* Returns the winding rule. TrueType glyphs always use the non-zero
* winding rule, so this method will always return {@link
* PathIterator#WIND_NON_ZERO}.
*/
public int getWindingRule()
{
return PathIterator.WIND_NON_ZERO;
}
public boolean isDone()
{
return (state != EMIT_CLOSE) && (curPoint >= numPoints);
}
public void next()
{
boolean onCurve;
/* If the current point is the end of a segment, and no SEG_CLOSE
* has been emitted yet, this will be the next segment.
*/
if (zone.isContourEnd(curPoint) && (state != EMIT_CLOSE))
{
state = EMIT_CLOSE;
return;
}
/* If the previously emitted segment was a SEG_CLOSE, we are now
* at the beginning of a new contour.
*/
if (state == EMIT_CLOSE)
{
contourStart = ++curPoint;
state = EMIT_MOVETO;
return;
}
onCurve = zone.isOnCurve(curPoint);
/* If the last segment was a moveto, and the current point
* (which is the first point in the contour) is off-curve,
* we need to emit a quadto segment for the first point.
*/
if ((state == EMIT_MOVETO) && !onCurve)
{
state = EMIT_SEGMENT;
return;
}
curPoint++;
/* If the last point has been off-curve, and the now current
* point is on-curve, the last segment was a quadto that
* had the now current point at its end. In this case, we can
* skip a segment.
*/
if (!onCurve && zone.isOnCurve(curPoint))
{
/* But if the skipped point is the end of a contour, we must not
* skip the SEG_CLOSE. An example where this matters is the 'o'
* glyph in the Helvetica font face that comes with MacOS X
* 10.1.5.
*/
if (zone.isContourEnd(curPoint))
{
state = EMIT_CLOSE;
return;
}
curPoint++;
}
state = EMIT_SEGMENT;
}
/**
* Determines the successor of the current point in the current
* contour. The successor of the last point in a contour is the
* start of that contour.
*
* @return the number of the point that follows the current point in
* the same contour.
*/
private int getSuccessor(int p)
{
if (zone.isContourEnd(p))
return contourStart;
else
return p + 1;
}
/**
* Retrieves the current path segment using single-precision
* coordinate values.
*/
public int currentSegment(float[] coords)
{
switch (state)
{
case EMIT_CLOSE:
return PathIterator.SEG_CLOSE;
case EMIT_MOVETO:
return getStartSegment(curPoint, coords);
default:
return getSegment(curPoint, coords);
}
}
/**
* A helper array that is used by {@link
* #currentSegment(double[])}.
*/
float[] floats;
/**
* Retrieves the current path segment using double-precision
* coordinate values.
*/
public int currentSegment(double[] coords)
{
if (floats == null)
floats = new float[6];
int result;
result = currentSegment(floats);
for (int i = 0; i < 6; i++)
coords[i] = floats[i];
return result;
}
/**
* Returns the segment for the specified point.
*
* <p><img src="doc-files/ZonePathIterator-1.png" width="426"
* height="194" alt="An example curve" /></p>
*
* <p>If <code>cur</code> is an on-curve point, the returned segment
* is a straight line to <code>cur</code>. In the illustration, this
* would be the case for <code>cur = 4</code>.</p>
*
* <p>If <code>cur</code> is an off-curve point, and
* <code>cur</code>&#x2019;s successor <code>succ</code> is also
* off-curve, the returned segment is a quadratic B&eacute;zier
* spline whose control point is <code>cur</code>, and whose end
* point is located at the middle of the line connecting
* <code>cur</code> and <code>succ</code>. In the illustration,
* this would be the case for <code>cur = 5</code>.</p>
*
* <p>If <code>cur</code> is an off-curve point, and
* <code>cur</code>&#x2019;s successor <code>succ</code> is
* on-curve, the returned segment is a quadratic B&eacute;zier
* spline whose control point is <code>cur</code>, and whose end
* point is <code>succ</code>. In the illustration, this would
* be the case for <code>cur = 6</code>.</p>
*
* @return either <code>PathIterator.SEG_LINETO</code> or
* <code>PathIterator.SEG_QUADTO</code>.
*/
private int getSegment(int cur, float[] coords)
{
int curX, curY;
int succ, succX, succY;
curX = zone.getX(cur);
curY = zone.getY(cur);
coords[0] = Fixed.floatValue(curX);
coords[1] = Fixed.floatValue(curY);
if (zone.isOnCurve(cur))
return PathIterator.SEG_LINETO;
succ = getSuccessor(cur);
succX = zone.getX(succ);
succY = zone.getY(succ);
if (zone.isOnCurve(succ))
{
coords[2] = Fixed.floatValue(succX);
coords[3] = Fixed.floatValue(succY);
}
else
{
coords[2] = Fixed.floatValue((curX + succX) / 2);
coords[3] = Fixed.floatValue((curY + succY) / 2);
}
return PathIterator.SEG_QUADTO;
}
/**
* Returns the start segment for the contour which starts
* at the specified point.
*
* <p>If the contour starts with an on-curve point, the returned
* segment is a <code>SEG_MOVETO</code> to that point.</p>
*
* <p>If the contour starts with an off-curve point, and the contour
* ends with an on-curve point, the returned segment is a
* <code>SEG_MOVETO</code> to the end point.</p>
*
* <p>If the contour starts with an off-curve point, and the contour
* also ends with an off-curve point, the returned segment is a
* <code>SEG_MOVETO</code> to the location at the middle between the
* start and end points of the contour.</p>
*
* @return <code>PathIterator.SEG_MOVETO</code>.
*/
private int getStartSegment(int contourStart, float[] coords)
{
int x, y;
if (zone.isOnCurve(contourStart))
{
x = zone.getX(contourStart);
y = zone.getY(contourStart);
}
else
{
/* Find the last point of the current contour. */
int contourEnd = contourStart;
while (!zone.isContourEnd(contourEnd))
++contourEnd;
if (zone.isOnCurve(contourEnd))
{
/* An example is the 'o' glyph of the Helvetica which comes
* with Apple MacOS X 10.1.5.
*/
x = zone.getX(contourEnd);
y = zone.getY(contourEnd);
}
else
{
x = (zone.getX(contourStart) + zone.getX(contourEnd)) / 2;
y = (zone.getY(contourStart) + zone.getY(contourEnd)) / 2;
}
}
coords[0] = Fixed.floatValue(x);
coords[1] = Fixed.floatValue(y);
return PathIterator.SEG_MOVETO;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,316 @@
/* AlphaCompositeContext.java -- CompositeContext impl for AlphaComposite
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.java2d;
import java.awt.AWTError;
import java.awt.AlphaComposite;
import java.awt.CompositeContext;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
/**
* A CompositeContext implementation for {@link AlphaComposite}.
*
* @author Roman Kennke (kennke@aicas.com)
*/
public class AlphaCompositeContext
implements CompositeContext
{
/**
* The Composite object for which we perform compositing.
*/
private AlphaComposite composite;
/**
* The source color model.
*/
private ColorModel srcColorModel;
/**
* The destination color model.
*/
private ColorModel dstColorModel;
/**
* The blending factor for the source.
*/
private float fs;
/**
* The blending factor for the destination.
*/
private float fd;
/**
* Creates a new AlphaCompositeContext.
*
* @param aComp the AlphaComposite object
* @param srcCM the source color model
* @param dstCM the destination color model
*/
public AlphaCompositeContext(AlphaComposite aComp, ColorModel srcCM,
ColorModel dstCM)
{
composite = aComp;
srcColorModel = srcCM;
dstColorModel = dstCM;
// Determine the blending factors according to the rule in the
// AlphaComposite. For some rules the factors must be determined
// dynamically because they depend on the actual pixel value.
switch (composite.getRule())
{
case AlphaComposite.CLEAR:
fs = 0.F;
fd= 0.F;
break;
case AlphaComposite.DST:
fs = 0.F;
fd= 1.F;
break;
case AlphaComposite.DST_ATOP:
fs = 1.F; // Determined later as 1 - alpha_dst;
fd = 1.F; // Determined later as alpha_src;
break;
case AlphaComposite.DST_IN:
fs = 0.F;
fd = 0.F; // Determined later as alpha_src;
break;
case AlphaComposite.DST_OUT:
fs = 0.F;
fd = 0.F; // Determined later as 1 - alpha_src;
break;
case AlphaComposite.DST_OVER:
fs = 1.F; // Determined later as 1 - alpha_dst.
fd= 1.F;
break;
case AlphaComposite.SRC:
fs = 1.F;
fd= 0.F;
break;
case AlphaComposite.SRC_ATOP:
fs = 1.F; // Determined later as alpha_dst;
fd = 1.F; // Determined later as 1 - alpha_src;
break;
case AlphaComposite.SRC_IN:
fs = 0.F; // Determined later as alpha_dst;
fd = 0.F;
break;
case AlphaComposite.SRC_OUT:
fs = 0.F; // Determined later as 1 - alpha_dst;
fd = 0.F;
break;
case AlphaComposite.SRC_OVER:
fs = 1.F;
fd= 1.F; // Determined later as 1 - alpha_src.
break;
case AlphaComposite.XOR:
fs = 1.F; // Determined later as 1 - alpha_dst.
fd= 1.F; // Determined later as 1 - alpha_src.
break;
default:
throw new AWTError("Illegal AlphaComposite rule");
}
}
/**
* Releases all resources held by this composite object.
*/
public void dispose()
{
// Nothing to do here yet.
}
/**
* Performs compositing according to the rules specified in the
* AlphaComposite from the constructor.
*/
public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
{
// TODO: This implementation is very general and highly inefficient. There
// are two possible ways to optimize this:
// 1. Special cased implementations for common ColorModels and transfer
// types.
// 2. Native implementation.
int x0 = src.getMinX();
int y0 = src.getMinY();
int width = src.getWidth();
int height = src.getHeight();
int x1 = x0 + width;
int y1 = y0 + height;
Object srcPixel = null;
Object dstPixel = null;
// Prepare the array that holds the color and alpha components of the
// source pixels.
float[] srcComponents;
int srcComponentsLength = srcColorModel.getNumComponents();
if (! srcColorModel.hasAlpha())
srcComponentsLength += 1;
srcComponents = new float[srcComponentsLength];
// Prepare the array that holds the color and alpha components of the
// destination pixels.
float[] dstComponents;
int dstComponentsLength = dstColorModel.getNumComponents();
if (! dstColorModel.hasAlpha())
dstComponentsLength += 1;
dstComponents = new float[dstComponentsLength];
if (srcComponentsLength != dstComponentsLength)
throw new AWTError("The color models of the source and destination have"
+ "incompatible number of color components");
int srcTransferType = srcColorModel.getTransferType();
int dstTransferType = dstColorModel.getTransferType();
for (int y = y0; y < y1; y++)
{
for (int x = x0; x < x1; x++)
{
// Fetch source pixel.
srcPixel = src.getDataElements(x, y, (int[]) srcPixel);
// Fetch destination pixel.
dstPixel = dstIn.getDataElements(x, y, dstPixel);
// Get normalized components. This is the only type that is
// guaranteed to be supported by all ColorModels.
srcComponents =
srcColorModel.getNormalizedComponents(srcPixel, srcComponents, 0);
if (! srcColorModel.hasAlpha())
srcComponents[srcComponentsLength - 1] = 1.0F;
dstComponents =
dstColorModel.getNormalizedComponents(dstPixel, dstComponents, 0);
if (! dstColorModel.hasAlpha())
dstComponents[dstComponentsLength - 1] = 1.0F;
// Prepare the input.
float compositeAlpha = composite.getAlpha();
srcComponents[srcComponentsLength - 1] *= compositeAlpha;
if (srcColorModel.isAlphaPremultiplied())
{
for (int i = srcComponentsLength - 2; i >= 0; i--)
srcComponents[i] *= compositeAlpha;
}
else
{
for (int i = srcComponentsLength - 1; i >= 0; i--)
srcComponents[i] *= srcComponents[srcComponentsLength - 1];
}
if (! dstColorModel.isAlphaPremultiplied())
{
for (int i = dstComponentsLength - 2; i >= 0; i--)
dstComponents[i] *= dstComponents[dstComponents.length - 1];
}
// Determine the blending factors according to the rule in the
// AlphaComposite. For some rules the factors must be determined
// dynamically because they depend on the actual pixel value.
float srcAlpha = srcComponents[srcComponentsLength - 1];
float dstAlpha = dstComponents[dstComponentsLength - 1];
switch (composite.getRule())
{
case AlphaComposite.DST_ATOP:
fs = 1.F - dstAlpha;
fd = srcAlpha;
break;
case AlphaComposite.DST_IN:
fd = srcAlpha;
break;
case AlphaComposite.DST_OUT:
fd = 1.F - srcAlpha;
break;
case AlphaComposite.DST_OVER:
fs = 1.F - dstAlpha;
break;
case AlphaComposite.SRC_ATOP:
fs = srcAlpha;
fd = 1.F - srcAlpha;
break;
case AlphaComposite.SRC_IN:
fs = dstAlpha;
break;
case AlphaComposite.SRC_OUT:
fs = 1.F - dstAlpha;
break;
case AlphaComposite.SRC_OVER:
fd= 1.F - srcAlpha;
break;
case AlphaComposite.XOR:
fs = 1.F - dstAlpha;
fd= 1.F - srcAlpha;
break;
default:
// For the other cases the factors have already been determined
// in the constructor.
}
// Apply the blending equation to the pixels.
for (int i = 0; i < srcComponentsLength; i++)
{
dstComponents[i] = srcComponents[i] * fs
+ dstComponents[i] * fd;
}
// Convert the result back when the destination is not
// alpha-premultiplied.
dstAlpha = dstComponents[dstComponentsLength - 1];
if (!dstColorModel.isAlphaPremultiplied() && dstAlpha != 0.F)
{
for (int i = 0; i < dstComponentsLength - 1; i++)
{
dstComponents[i] = dstComponents[i] / dstAlpha;
}
}
// Store the result in the destination raster.
dstPixel = dstColorModel.getDataElements(dstComponents, 0,
dstPixel);
dstOut.setDataElements(x, y, dstPixel);
} // End X loop.
} // End Y loop.
}
}

View file

@ -0,0 +1,128 @@
/* CubicSegment.java -- Cubic segment used for BasicStroke
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.java2d;
import java.awt.geom.Point2D;
/**
* Cubic Bezier curve segment
*/
public class CubicSegment extends Segment
{
public Point2D cp1; // control points
public Point2D cp2; // control points
/**
* Constructor - takes coordinates of the starting point,
* first control point, second control point and end point,
* respecively.
*/
public CubicSegment(double x1, double y1, double c1x, double c1y,
double c2x, double c2y, double x2, double y2)
{
super();
P1 = new Point2D.Double(x1, y1);
P2 = new Point2D.Double(x2, y2);
cp1 = new Point2D.Double(c1x, c1y);
cp2 = new Point2D.Double(c2x, c2y);
}
public CubicSegment(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2)
{
super();
P1 = p1;
P2 = p2;
this.cp1 = cp1;
this.cp2 = cp2;
}
/**
* Clones this segment
*/
public Object clone()
{
return new CubicSegment(P1.getX(), P1.getY(), cp1.getX(), cp1.getY(),
cp2.getX(), cp2.getY(), P2.getX(), P2.getY());
}
/**
* Get the "top" and "bottom" segments of this segment.
* First array element is p0 + normal, second is p0 - normal.
*/
public Segment[] getDisplacedSegments(double radius)
{
this.radius = radius;
double x0 = P1.getX();
double y0 = P1.getY();
double x1 = cp1.getX();
double y1 = cp1.getY();
double x2 = cp2.getX();
double y2 = cp2.getY();
double x3 = P2.getX();
double y3 = P2.getY();
double[] p1 = normal(x0, y0, x1, y1);
double[] p2 = normal(x2, y2, x3, y3);
// FIXME: Doesn't compile.
// return new Segment[]{s1, s2};
return new Segment[0];
}
public void reverse()
{
Point2D temp = P1;
P1 = P2;
P2 = temp;
temp = cp1;
cp1 = cp2;
cp2 = temp;
}
public double[] first()
{
return new double[]{cp1.getX(), cp1.getY()};
}
public double[] last()
{
return new double[]{cp2.getX(), cp2.getY()};
}
} // class CubicSegment

View file

@ -0,0 +1,103 @@
/* LineSegment.java -- Line segment used for BasicStroke
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.java2d;
import java.awt.geom.Point2D;
public class LineSegment extends Segment
{
public LineSegment(double x1, double y1, double x2, double y2)
{
super();
P1 = new Point2D.Double(x1, y1);
P2 = new Point2D.Double(x2, y2);
}
public LineSegment(Point2D p1, Point2D p2)
{
super();
P1 = (Point2D) p1.clone();
P2 = (Point2D) p2.clone();
}
/**
* Clones this segment
*/
public Object clone()
{
return new LineSegment(P1, P2);
}
/**
* Get the "top" and "bottom" segments of this segment.
* First array element is p0 + normal, second is p0 - normal.
*/
public Segment[] getDisplacedSegments(double radius)
{
this.radius = radius;
double x0 = P1.getX();
double y0 = P1.getY();
double x1 = P2.getX();
double y1 = P2.getY();
double[] p = normal(x0, y0, x1, y1);
Segment s1 = (new LineSegment(x0 + p[0], y0 + p[1],
x1 + p[0], y1 + p[1] ));
Segment s2 = (new LineSegment(x0 - p[0], y0 - p[1],
x1 - p[0], y1 - p[1] ));
return new Segment[]{s1, s2};
}
public void reverse()
{
Point2D p = P1;
P1 = P2;
P2 = p;
}
public double[] first()
{
return new double[]{P2.getX(), P2.getY()};
}
public double[] last()
{
return new double[]{P1.getX(), P1.getY()};
}
} // class LineSegment

View file

@ -0,0 +1,117 @@
/* PolyEdge.java -- An edge in a polygon, used for polygon filling
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.java2d;
/**
* An edge in a polygon. This is used by the scanline conversion algorithm
* implemented in {@link AbstractGraphics2D#rawFillShape}.
*
* @author Roman Kennke (kennke@aicas.com)
*/
public class PolyEdge
implements Comparable
{
/**
* The start and end coordinates of the edge. y0 is always smaller or equal
* than y1.
*/
public double x0, y0, x1, y1;
/**
* The slope of the edge. This is dx / dy.
*/
double slope;
/**
* The intersection of this edge with the current scanline.
*/
double xIntersection;
/**
* Creates a new PolyEdge with the specified coordinates.
*
* @param x0 the starting point, x coordinate
* @param y0 the starting point, y coordinate
* @param x1 the end point, x coordinate
* @param y1 the end point, y coordinate
*/
PolyEdge(double x0, double y0, double x1, double y1)
{
if (y0 < y1)
{
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
}
else
{
this.x0 = x1;
this.y0 = y1;
this.x1 = x0;
this.y1 = y0;
}
slope = (this.x1 - this.x0) / (this.y1 - this.y0);
if (this.y0 == this.y1) // Horizontal edge.
xIntersection = Math.min(this.x0, this.x1);
else
xIntersection = this.x0 + slope * (Math.ceil(this.y0) - this.y0);
}
/**
* Sorts PolyEdges by the x coordinate from the minimum x value.
*/
public int compareTo(Object o)
{
PolyEdge other = (PolyEdge) o;
int comp = 0;
if (x0 < other.x0)
comp = -1;
else if (x0 > other.x0)
comp = 1;
return comp;
}
public String toString()
{
return "Edge: " + x0 + ", " + y0 + ", " + x1 + ", " + y1 + ", slope: "
+ slope + ", xIntersection: " + xIntersection;
}
}

View file

@ -0,0 +1,70 @@
/* PolyEdgeComparator.java -- Sorts PolyEdges by their current intersection
points
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.java2d;
import java.util.Comparator;
/**
* Sorts {@link PolyEdge}s by their current intersection points.
*
* @author Roman Kennke (kennke@aicas.com)
*/
public class PolyEdgeComparator
implements Comparator
{
/**
* The current scanline.
*/
int y;
public int compare(Object o1, Object o2)
{
PolyEdge edge1 = (PolyEdge) o1;
PolyEdge edge2 = (PolyEdge) o2;
int comp = 0;
if (edge1.xIntersection < edge2.xIntersection)
comp = -1;
else if (edge1.xIntersection > edge2.xIntersection)
comp = 1;
return comp;
}
}

View file

@ -0,0 +1,213 @@
/* QuadSegment.java -- QuadCurve segment used for BasicStroke
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.java2d;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
/**
* Quadratic Bezier curve segment
*
* Note: Most peers don't support quadratics directly, so it might make
* sense to represent them as cubics internally and just be done with it.
* I think we should be peer-agnostic, however, and stay faithful to the
* input geometry types as far as possible.
*/
public class QuadSegment extends Segment
{
public Point2D cp; // control point
/**
* Constructor, takes the coordinates of the start, control,
* and end point, respectively.
*/
public QuadSegment(double x1, double y1, double cx, double cy, double x2,
double y2)
{
super();
P1 = new Point2D.Double(x1, y1);
P2 = new Point2D.Double(x2, y2);
cp = new Point2D.Double(cx, cy);
}
public QuadSegment(Point2D p1, Point2D cp, Point2D p2)
{
super();
P1 = p1;
P2 = p2;
this.cp = cp;
}
public QuadSegment(QuadCurve2D curve)
{
super();
P1 = curve.getP1();
P2 = curve.getP2();
this.cp = curve.getCtrlPt();
}
/**
* Clones this segment
*/
public Object clone()
{
return new QuadSegment(P1.getX(), P1.getY(), cp.getX(), cp.getY(),
P2.getX(), P2.getY());
}
/**
* Get the "top" and "bottom" segments of a given segment.
* First array element is p0 + normal, second is p0 - normal.
*/
public Segment[] getDisplacedSegments(double radius)
{
this.radius = radius;
double x0 = P1.getX();
double y0 = P1.getY();
double x1 = cp.getX();
double y1 = cp.getY();
double x2 = P2.getX();
double y2 = P2.getY();
QuadCurve2D left = new QuadCurve2D.Double();
QuadCurve2D right = new QuadCurve2D.Double();
QuadCurve2D orig = new QuadCurve2D.Double(x0, y0, x1, y1, x2, y2);
orig.subdivide(left, right);
QuadSegment s1 = offsetSubdivided(left, true);
QuadSegment s2 = offsetSubdivided(left, false);
s1.add( offsetSubdivided(right, true) );
s2.add( offsetSubdivided(right, false) );
return new Segment[]{s1, s2};
}
private QuadSegment offsetSubdivided(QuadCurve2D curve, boolean plus)
{
double[] n1 = normal(curve.getX1(), curve.getY1(),
curve.getCtrlX(), curve.getCtrlY());
double[] n2 = normal(curve.getCtrlX(), curve.getCtrlY(),
curve.getX2(), curve.getY2());
Point2D cp;
QuadSegment s;
if( plus )
{
cp = lineIntersection(curve.getX1() + n1[0],
curve.getY1() + n1[1],
curve.getCtrlX() + n1[0],
curve.getCtrlY() + n1[1],
curve.getCtrlX() + n2[0],
curve.getCtrlY() + n2[1],
curve.getX2() + n2[0],
curve.getY2() + n2[1], true);
s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
cp.getX(), cp.getY(),
curve.getX2() + n2[0], curve.getY2() + n2[1]);
}
else
{
cp = lineIntersection(curve.getX1() - n1[0],
curve.getY1() - n1[1],
curve.getCtrlX() - n1[0],
curve.getCtrlY() - n1[1],
curve.getCtrlX() - n2[0],
curve.getCtrlY() - n2[1],
curve.getX2() - n2[0],
curve.getY2() - n2[1], true);
s = new QuadSegment(curve.getX1() - n1[0], curve.getY1() - n1[1],
cp.getX(), cp.getY(),
curve.getX2() - n2[0], curve.getY2() - n2[1]);
}
return s;
}
private Point2D lineIntersection(double X1, double Y1,
double X2, double Y2,
double X3, double Y3,
double X4, double Y4,
boolean infinite)
{
double x1 = X1;
double y1 = Y1;
double rx = X2 - x1;
double ry = Y2 - y1;
double x2 = X3;
double y2 = Y3;
double sx = X4 - x2;
double sy = Y4 - y2;
double determinant = sx * ry - sy * rx;
double nom = (sx * (y2 - y1) + sy * (x1 - x2));
// lines can be considered parallel.
if (Math.abs(determinant) < 1E-6)
return null;
nom = nom / determinant;
// check if lines are within the bounds
if(!infinite && (nom > 1.0 || nom < 0.0))
return null;
return new Point2D.Double(x1 + nom * rx, y1 + nom * ry);
}
public void reverse()
{
Point2D p = P1;
P1 = P2;
P2 = p;
}
public double[] first()
{
return new double[]{cp.getX(), cp.getY()};
}
public double[] last()
{
return new double[]{cp.getX(), cp.getY()};
}
}

View file

@ -0,0 +1,101 @@
/* RasterGraphics.java -- A Graphics2D impl for Rasters
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.java2d;
import java.awt.GraphicsConfiguration;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
/**
* A Graphics2D implementation that operates on Raster objects. This is
* primarily used for BufferedImages, but can theoretically be used on
* arbitrary WritableRasters.
*
* @author Roman Kennke (kennke@aicas.com)
*/
public class RasterGraphics
extends AbstractGraphics2D
{
/**
* The raster on which we operate.
*/
private WritableRaster raster;
/**
* The color model of this Graphics instance.
*/
private ColorModel colorModel;
public RasterGraphics(WritableRaster r, ColorModel cm)
{
raster = r;
colorModel = cm;
}
/**
* Returns the color model of this Graphics object.
*
* @return the color model of this Graphics object
*/
protected ColorModel getColorModel()
{
return colorModel;
}
/**
* Returns a WritableRaster that is used by this class to perform the
* rendering in. It is not necessary that the target surface immediately
* reflects changes in the raster. Updates to the raster are notified via
* {@link AbstractGraphics2D#updateRaster}.
*
* @return the destination raster
*/
protected WritableRaster getDestinationRaster()
{
return raster;
}
public GraphicsConfiguration getDeviceConfiguration()
{
// TODO Auto-generated method stub
return null;
}
}

View file

@ -0,0 +1,131 @@
/* Segment.java -- Abstract segment used for BasicStroke
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.java2d;
import java.awt.geom.Point2D;
public abstract class Segment implements Cloneable
{
// segment type, PathIterator segment types are used.
public Point2D P1;
public Point2D P2;
public Segment next;
public Segment last;
protected double radius;
public Segment()
{
P1 = P2 = null;
next = null;
last = this;
}
public void add(Segment newsegment)
{
last.next = newsegment;
last = last.next;
}
/**
* Reverses the orientation of the whole polygon
*/
public void reverseAll()
{
reverse();
Segment v = next;
Segment former = this;
next = null;
while (v != null)
{
v.reverse();
v.last = this;
Segment oldnext = v.next;
v.next = former;
former = v;
v = oldnext; // move to the next in list
}
}
public String toString()
{
return "Segment:"+P1+", "+P2;
}
/**
* Get the normal vector to the slope of the line.
* Returns: 0.5*width*(norm of derivative of the (x0,y0)-(x1,y1) vector)
*/
protected double[] normal(double x0, double y0, double x1, double y1)
{
double dx = (x1 - x0);
double dy = (y1 - y0);
if( dy == 0 )
{
dy = radius * ((dx > 0)?1:-1);
dx = 0;
}
else if( dx == 0 )
{
dx = radius * ((dy > 0)?-1:1);
dy = 0;
}
else
{
double N = Math.sqrt(dx * dx + dy * dy);
double odx = dx;
dx = -radius * dy / N;
dy = radius * odx / N;
}
return new double[]{ dx, dy };
}
public abstract void reverse();
/**
* Get the "top" and "bottom" segments of a segment.
* First array element is p0 + normal, second is p0 - normal.
*/
public abstract Segment[] getDisplacedSegments(double radius);
public abstract double[] first();
public abstract double[] last();
}

View file

@ -1,5 +1,5 @@
/* GLightweightPeer.java --
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -54,11 +54,14 @@ import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.PaintEvent;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.awt.image.VolatileImage;
import java.awt.peer.ComponentPeer;
import java.awt.peer.ContainerPeer;
import java.awt.peer.LightweightPeer;
@ -79,7 +82,7 @@ import java.awt.peer.LightweightPeer;
* Lightweight components are painted directly onto their parent
* containers through an Image object provided by the toolkit.
*/
public class GLightweightPeer
public class GLightweightPeer
implements LightweightPeer, ContainerPeer
{
private Component comp;
@ -247,7 +250,25 @@ public class GLightweightPeer
public void setBounds(int x, int y, int width, int height) {}
public void setCursor(Cursor cursor) {}
/**
* Sets the cursor on the heavy-weight parent peer.
* Called by the MouseListener on mouse enter.
*/
public void setCursor(Cursor cursor)
{
Component p = comp.getParent();
while (p != null && p.isLightweight())
p = p.getParent();
if (p != null)
{
// Don't actually change the cursor of the component
// otherwise other childs inherit this cursor.
ComponentPeer peer = p.getPeer();
if (peer != null)
peer.setCursor(cursor);
}
}
public void setEnabled(boolean enabled) {}

View file

@ -110,14 +110,10 @@ public class GdkFontMetrics extends FontMetrics
return stringWidth (new String (data, off, len));
}
/*
Sun's Motif implementation always returns 0 or 1 here (???), but
going by the X11 man pages, it seems as though we should return
font.ascent + font.descent.
*/
public int getLeading ()
{
return 1;
// Sun always returns 0.
return 0;
}
public int getAscent ()

View file

@ -1,5 +1,5 @@
/* GdkFontPeer.java -- Implements FontPeer with GTK+
Copyright (C) 1999, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 1999, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -43,6 +43,7 @@ import gnu.java.awt.peer.ClasspathFontPeer;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
@ -157,7 +158,7 @@ public class GdkFontPeer extends ClasspathFontPeer
public String getPostScriptName(Font font)
{
return null;
return this.familyName;
}
public boolean canDisplay (Font font, char c)
@ -301,7 +302,9 @@ public class GdkFontPeer extends ClasspathFontPeer
public FontMetrics getFontMetrics (Font font)
{
return new GdkFontMetrics (font);
// Get the font metrics through GtkToolkit to take advantage of
// the metrics cache.
return Toolkit.getDefaultToolkit().getFontMetrics (font);
}
}

View file

@ -48,6 +48,7 @@ import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.text.AttributedCharacterIterator;
@ -218,8 +219,10 @@ public class GdkGraphics extends Graphics
public boolean drawImage (Image img, int x, int y,
Color bgcolor, ImageObserver observer)
{
return drawImage(img, x, y, img.getWidth(null), img.getHeight(null),
bgcolor, observer);
if (img != null)
return drawImage(img, x, y, img.getWidth(null), img.getHeight(null),
bgcolor, observer);
return false;
}
public boolean drawImage (Image img, int x, int y, ImageObserver observer)
@ -227,16 +230,19 @@ public class GdkGraphics extends Graphics
return drawImage (img, x, y, null, observer);
}
public boolean drawImage (Image img, int x, int y, int width, int height,
Color bgcolor, ImageObserver observer)
public boolean drawImage(Image img, int x, int y, int width, int height,
Color bgcolor, ImageObserver observer)
{
if (img instanceof GtkImage)
return ((GtkImage)img).drawImage (this, x, y, width, height,
bgcolor, observer);
else
return (new GtkImage(img.getSource())).drawImage (this, x, y,
width, height,
bgcolor, observer);
if (img != null)
{
if (img instanceof GtkImage)
return ((GtkImage) img).drawImage(this, x, y, width, height, bgcolor,
observer);
return (new GtkImage(img.getSource())).drawImage(this, x, y, width,
height, bgcolor,
observer);
}
return false;
}
public boolean drawImage (Image img, int x, int y, int width, int height,
@ -249,14 +255,16 @@ public class GdkGraphics extends Graphics
int sx1, int sy1, int sx2, int sy2,
Color bgcolor, ImageObserver observer)
{
if (img instanceof GtkImage)
return ((GtkImage)img).drawImage(this, dx1, dy1, dx2, dy2,
sx1, sy1, sx2, sy2, bgcolor, observer);
else
return (new GtkImage(img.getSource())).drawImage(this, dx1, dy1,
dx2, dy2,
sx1, sy1, sx2, sy2,
bgcolor, observer);
if (img != null)
{
if (img instanceof GtkImage)
return ((GtkImage) img).drawImage(this, dx1, dy1, dx2, dy2, sx1, sy1,
sx2, sy2, bgcolor, observer);
return (new GtkImage(img.getSource())).drawImage(this, dx1, dy1, dx2,
dy2, sx1, sy1, sx2,
sy2, bgcolor, observer);
}
return false;
}
public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2,
@ -373,7 +381,9 @@ public class GdkGraphics extends Graphics
public FontMetrics getFontMetrics (Font font)
{
return new GdkFontMetrics (font);
// Get the font metrics through GtkToolkit to take advantage of
// the metrics cache.
return Toolkit.getDefaultToolkit().getFontMetrics (font);
}
native void setClipRectangle (int x, int y, int width, int height);

View file

@ -1229,7 +1229,10 @@ public class GdkGraphics2D extends Graphics2D
drawPixels(pixels, r.getWidth(), r.getHeight(), r.getWidth(), i2u);
updateBufferedImage();
// Cairo seems loosing the current color.
setColor(fg);
return true;
}

View file

@ -1,5 +1,5 @@
/* GdkPixbufDecoder.java -- Image data decoding object
Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -82,6 +82,14 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
initStaticState ();
}
/**
* Lock that should be held for all gdkpixbuf operations. We don't use
* the global gdk_threads_enter/leave functions since gdkpixbuf
* operations can be done in parallel to drawing and manipulating gtk
* widgets.
*/
static Object pixbufLock = new Object();
static native void initStaticState();
private final int native_state = GtkGenericPeer.getUniqueInteger ();
@ -92,6 +100,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
Vector curr;
// interface to GdkPixbuf
// These native functions should be called with the pixbufLock held.
native void initState ();
native void pumpBytes (byte[] bytes, int len) throws IOException;
native void pumpDone () throws IOException;
@ -171,11 +180,26 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
byte bytes[] = new byte[4096];
int len = 0;
initState();
synchronized(pixbufLock)
{
initState();
}
needsClose = true;
// Note: We don't want the pixbufLock while reading from the InputStream.
while ((len = is.read (bytes)) != -1)
pumpBytes (bytes, len);
pumpDone();
{
synchronized(pixbufLock)
{
pumpBytes (bytes, len);
}
}
synchronized(pixbufLock)
{
pumpDone();
}
needsClose = false;
for (int i = 0; i < curr.size (); i++)
@ -189,7 +213,10 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
public void finalize()
{
finish(needsClose);
synchronized(pixbufLock)
{
finish(needsClose);
}
}
@ -495,8 +522,11 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
}
processImageStarted(1);
streamImage(pixels, this.ext, width, height, model.hasAlpha(),
(DataOutput) this.getOutput());
synchronized(pixbufLock)
{
streamImage(pixels, this.ext, width, height, model.hasAlpha(),
(DataOutput) this.getOutput());
}
processImageComplete();
}
}

View file

@ -38,61 +38,22 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
import java.awt.AWTEvent;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.PaintEvent;
import java.awt.peer.CanvasPeer;
public class GtkCanvasPeer extends GtkComponentPeer implements CanvasPeer
{
native void create ();
native void realize ();
public GtkCanvasPeer (Canvas c)
{
super (c);
}
public Graphics getGraphics ()
{
if (GtkToolkit.useGraphics2D ())
return new GdkGraphics2D (this);
else
return new GdkGraphics (this);
}
public void handleEvent (AWTEvent event)
{
int id = event.getID();
switch (id)
{
case PaintEvent.PAINT:
case PaintEvent.UPDATE:
{
try
{
Graphics g = getGraphics ();
g.setClip (((PaintEvent)event).getUpdateRect());
if (id == PaintEvent.PAINT)
awtComponent.paint (g);
else
awtComponent.update (g);
g.dispose ();
}
catch (InternalError e)
{
System.err.println (e);
}
}
break;
}
}
/* Preferred size for a drawing widget is always what the user requested */
// Preferred size for a drawing widget is always what the user
// requested.
public Dimension getPreferredSize ()
{
return awtComponent.getSize ();

View file

@ -1,5 +1,5 @@
/* GtkClipboard.java
Copyright (C) 1999, 2005 Free Software Foundation, Inc.
Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -48,59 +48,85 @@ import java.util.Iterator;
public class GtkClipboard extends Clipboard
{
/**
* The one and only gtk+ clipboard instance for the CLIPBOARD selection.
*/
final static GtkClipboard clipboard = new GtkClipboard("System Clipboard");
/**
* The one and only gtk+ clipboard instance for the PRIMARY selection.
*/
final static GtkClipboard selection = new GtkClipboard("System Selection");
// Given to the native side so it can signal special targets that
// can be converted to one of the special predefined DataFlavors.
static final String stringMimeType;
static final String imageMimeType;
static final String filesMimeType;
static final String stringMimeType
= DataFlavor.stringFlavor.getMimeType();
static final String imageMimeType
= DataFlavor.imageFlavor.getMimeType();
static final String filesMimeType
= DataFlavor.javaFileListFlavor.getMimeType();
// Indicates whether the results of the clipboard selection can be
// cached by GtkSelection. True if
// gdk_display_supports_selection_notification.
static final boolean canCache;
static
{
stringMimeType = DataFlavor.stringFlavor.getMimeType();
imageMimeType = DataFlavor.imageFlavor.getMimeType();
filesMimeType = DataFlavor.javaFileListFlavor.getMimeType();
canCache = initNativeState(stringMimeType, imageMimeType, filesMimeType);
}
/**
* The one and only gtk+ clipboard instance.
*/
private static GtkClipboard instance = new GtkClipboard();
static final boolean canCache = initNativeState(clipboard, selection,
stringMimeType,
imageMimeType,
filesMimeType);
/**
* Creates the clipboard and sets the initial contents to the
* current gtk+ selection.
*/
private GtkClipboard()
private GtkClipboard(String name)
{
super("System Clipboard");
setContents(new GtkSelection(), null);
super(name);
setContents(new GtkSelection(this), null);
}
/**
* Returns the one and only GtkClipboard instance.
* Returns the one and only GtkClipboard instance for the CLIPBOARD
* selection.
*/
static GtkClipboard getInstance()
static GtkClipboard getClipboardInstance()
{
return instance;
return clipboard;
}
/**
* Returns the one and only GtkClipboard instance for the PRIMARY
* selection.
*/
static GtkClipboard getSelectionInstance()
{
return selection;
}
/**
* Sets the GtkSelection facade as new contents of the clipboard.
* Called from gtk+ when another application grabs the clipboard and
* we loose ownership.
*
* @param cleared If true this is a clear event (someone takes the
* clipboard from us) otherwise it is an owner changed event.
*/
private static void setSystemContents()
private synchronized void setSystemContents(boolean cleared)
{
GtkClipboardNotifier.announce();
// We need to notify clipboard owner listeners when we were the
// owner (the selection was explictly set) and someone takes the
// clipboard away from us and asks us the clear any held storage,
// or if we weren't the owner of the clipboard to begin with, but
// the clipboard contents changed. We could refine this and check
// whether the actual available formats did in fact change, but we
// assume listeners will check for that anyway (and if possible we
// ask to cache the available formats so even if multiple
// listeners check after a notification the overhead should be
// minimal).
boolean owner = ! (contents instanceof GtkSelection);
boolean needNotification = (cleared && owner) || (! cleared && ! owner);
if (needNotification)
GtkClipboardNotifier.announce(this);
}
/**
@ -146,15 +172,12 @@ public class GtkClipboard extends Clipboard
|| flavor.isRepresentationClassReader())
text = true;
// XXX - We only support automatic image conversion for
// GtkImages at the moment. So explicitly check that we have
// one.
if (! images && flavors[i].equals(DataFlavor.imageFlavor))
{
try
{
Object o = contents.getTransferData(DataFlavor.imageFlavor);
if (o instanceof GtkImage)
if (o instanceof Image)
images = true;
}
catch (UnsupportedFlavorException ufe)
@ -265,7 +288,11 @@ public class GtkClipboard extends Clipboard
try
{
return (GtkImage) contents.getTransferData(DataFlavor.imageFlavor);
Object o = contents.getTransferData(DataFlavor.imageFlavor);
if( o instanceof GtkImage )
return (GtkImage) o;
else
return new GtkImage(((Image)o).getSource());
}
catch (UnsupportedFlavorException ufe)
{
@ -384,11 +411,13 @@ public class GtkClipboard extends Clipboard
}
/**
* Initializes the gtk+ clipboard and caches any native side
* Initializes the gtk+ clipboards and caches any native side
* structures needed. Returns whether or not the contents of the
* Clipboard can be cached (gdk_display_supports_selection_notification).
*/
private static native boolean initNativeState(String stringTarget,
private static native boolean initNativeState(GtkClipboard clipboard,
GtkClipboard selection,
String stringTarget,
String imageTarget,
String filesTarget);
}

View file

@ -39,11 +39,15 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
import java.awt.datatransfer.*;
import java.util.*;
class GtkClipboardNotifier extends Thread
{
/** Whether or not to announce a GtkSelection change. */
private static boolean announceChange;
/** Whether to announce a new GtkSelection has been set for CLIPBOARD. */
static private boolean announceClipboardChange;
/** Whether to announce a new GtkSelection has been set for PRIMARY. */
static private boolean announcePrimaryChange;
/**
* The one and only instance. All operations are synchronized on
@ -64,24 +68,30 @@ class GtkClipboardNotifier extends Thread
/**
* Notifies that a new GtkSelection has to be announced.
*
* @param clipboard either the GtkClipboard.clipboard or the
* GtkClipboard.selection.
*/
static void announce()
static void announce(GtkClipboard clipboard)
{
synchronized (notifier)
{
announceChange = true;
if (clipboard == GtkClipboard.clipboard)
announceClipboardChange = true;
else
announcePrimaryChange = true;
notifier.notifyAll();
}
}
public void run()
{
final GtkClipboard clipboard = GtkClipboard.getInstance();
GtkClipboard clipboard;
while (true)
{
synchronized (this)
{
while (!announceChange)
while (! announceClipboardChange && ! announcePrimaryChange)
{
try
{
@ -92,14 +102,24 @@ class GtkClipboardNotifier extends Thread
// ignore
}
}
announceChange = false;
if (announceClipboardChange)
{
clipboard = GtkClipboard.clipboard;
announceClipboardChange = false;
}
else
{
clipboard = GtkClipboard.selection;
announcePrimaryChange = false;
}
}
// Do the actual announcement without the lock held. We will
// notice a new change after this notification has finished.
try
{
clipboard.setContents(new GtkSelection(), null);
clipboard.setContents(new GtkSelection(clipboard), null);
}
catch (Throwable t)
{

View file

@ -63,6 +63,7 @@ import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.PaintEvent;
import java.awt.event.TextEvent;
import java.awt.image.BufferedImage;
@ -86,8 +87,6 @@ public class GtkComponentPeer extends GtkGenericPeer
Insets insets;
boolean isInRepaint;
/* this isEnabled differs from Component.isEnabled, in that it
knows if a parent is disabled. In that case Component.isEnabled
may return true, but our isEnabled will always return false */
@ -100,8 +99,9 @@ public class GtkComponentPeer extends GtkGenericPeer
native void gtkWidgetGetPreferredDimensions (int[] dim);
native void gtkWindowGetLocationOnScreen (int[] point);
native void gtkWidgetGetLocationOnScreen (int[] point);
native void gtkWidgetSetCursor (int type);
native void gtkWidgetSetCursorUnlocked (int type);
native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y);
native void gtkWidgetSetCursorUnlocked (int type, GtkImage image,
int x, int y);
native void gtkWidgetSetBackground (int red, int green, int blue);
native void gtkWidgetSetForeground (int red, int green, int blue);
native void gtkWidgetSetSensitive (boolean sensitive);
@ -150,6 +150,9 @@ public class GtkComponentPeer extends GtkGenericPeer
setNativeEventMask ();
realize ();
if (awtComponent.isCursorSet())
setCursor ();
}
void setParentAndBounds ()
@ -176,16 +179,6 @@ public class GtkComponentPeer extends GtkGenericPeer
gtkWidgetSetParent (p);
}
void beginNativeRepaint ()
{
isInRepaint = true;
}
void endNativeRepaint ()
{
isInRepaint = false;
}
/*
* Set the bounds of this peer's AWT Component based on dimensions
* returned by the native windowing system. Most Components impose
@ -250,6 +243,8 @@ public class GtkComponentPeer extends GtkGenericPeer
return getToolkit().getFontMetrics(font);
}
// getGraphics may be overridden by derived classes but it should
// never return null.
public Graphics getGraphics ()
{
if (GtkToolkit.useGraphics2D ())
@ -291,30 +286,10 @@ public class GtkComponentPeer extends GtkGenericPeer
switch (id)
{
case PaintEvent.PAINT:
paintComponent((PaintEvent) event);
break;
case PaintEvent.UPDATE:
{
try
{
Graphics g = getGraphics();
if (!awtComponent.isShowing() || awtComponent.getWidth() < 1
|| awtComponent.getHeight() < 1 || g == null)
break;
g.setClip(((PaintEvent) event).getUpdateRect());
if (id == PaintEvent.PAINT)
awtComponent.paint(g);
else
awtComponent.update(g);
g.dispose();
}
catch (InternalError e)
{
System.err.println(e);
}
}
updateComponent((PaintEvent) event);
break;
case KeyEvent.KEY_PRESSED:
ke = (KeyEvent) event;
@ -328,7 +303,49 @@ public class GtkComponentPeer extends GtkGenericPeer
break;
}
}
// This method and its overrides are the only methods in the peers
// that should call awtComponent.paint.
protected void paintComponent (PaintEvent event)
{
// Do not call Component.paint if the component is not showing or
// if its bounds form a degenerate rectangle.
if (!awtComponent.isShowing()
|| (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
return;
// Creating and disposing a GdkGraphics every time paint is called
// seems expensive. However, the graphics state does not carry
// over between calls to paint, and resetting the graphics object
// may even be more costly than simply creating a new one.
Graphics g = getGraphics();
g.setClip(event.getUpdateRect());
awtComponent.paint(g);
g.dispose();
}
// This method and its overrides are the only methods in the peers
// that should call awtComponent.update.
protected void updateComponent (PaintEvent event)
{
// Do not call Component.update if the component is not showing or
// if its bounds form a degenerate rectangle.
if (!awtComponent.isShowing()
|| (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
return;
Graphics g = getGraphics();
g.setClip(event.getUpdateRect());
awtComponent.update(g);
g.dispose();
}
public boolean isFocusTraversable ()
{
return true;
@ -369,7 +386,7 @@ public class GtkComponentPeer extends GtkGenericPeer
public void repaint (long tm, int x, int y, int width, int height)
{
if (x == 0 && y == 0 && width == 0 && height == 0)
if (width < 1 || height < 1)
return;
if (tm <= 0)
@ -490,10 +507,28 @@ public class GtkComponentPeer extends GtkGenericPeer
public void setCursor (Cursor cursor)
{
if (Thread.currentThread() == GtkToolkit.mainThread)
gtkWidgetSetCursorUnlocked (cursor.getType ());
int x, y;
GtkImage image;
int type = cursor.getType();
if (cursor instanceof GtkCursor)
{
GtkCursor gtkCursor = (GtkCursor) cursor;
image = gtkCursor.getGtkImage();
Point hotspot = gtkCursor.getHotspot();
x = hotspot.x;
y = hotspot.y;
}
else
gtkWidgetSetCursor (cursor.getType ());
{
image = null;
x = 0;
y = 0;
}
if (Thread.currentThread() == GtkToolkit.mainThread)
gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y);
else
gtkWidgetSetCursor(cursor.getType(), image, x, y);
}
public void setEnabled (boolean b)
@ -532,7 +567,7 @@ public class GtkComponentPeer extends GtkGenericPeer
public void setVisible (boolean b)
{
// Only really set visible when component is bigger than zero pixels.
if (b)
if (b && ! (awtComponent instanceof Window))
{
Rectangle bounds = awtComponent.getBounds();
b = (bounds.width > 0) && (bounds.height > 0);
@ -561,10 +596,22 @@ public class GtkComponentPeer extends GtkGenericPeer
clickCount, popupTrigger));
}
/**
* Callback for component_scroll_cb.
*/
protected void postMouseWheelEvent(int id, long when, int mods,
int x, int y, int clickCount,
boolean popupTrigger,
int type, int amount, int rotation)
{
q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods,
x, y, clickCount, popupTrigger,
type, amount, rotation));
}
protected void postExposeEvent (int x, int y, int width, int height)
{
if (!isInRepaint)
q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
new Rectangle (x, y, width, height)));
}

View file

@ -99,11 +99,6 @@ public class GtkContainerPeer extends GtkComponentPeer
}
}
public Graphics getGraphics ()
{
return super.getGraphics();
}
public void beginLayout () { }
public void endLayout () { }
public boolean isPaintPending () { return false; }

View file

@ -0,0 +1,72 @@
/* GtkCursor.java -- Simple wrapper for custom cursor.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.peer.gtk;
import java.awt.Cursor;
import java.awt.Image;
import java.awt.Point;
/**
* Simple wrapper for custom Cursor.
*/
public class GtkCursor extends Cursor
{
private final GtkImage image;
private final Point hotspot;
GtkCursor(Image image, Point hotspot, String name)
{
super(name);
if (image instanceof GtkImage)
this.image = (GtkImage) image;
else
this.image = new GtkImage(image.getSource());
this.hotspot = hotspot;
}
GtkImage getGtkImage()
{
return image;
}
Point getHotspot()
{
return hotspot;
}
}

View file

@ -51,34 +51,6 @@ public class GtkDialogPeer extends GtkWindowPeer
{
super (dialog);
}
public Graphics getGraphics ()
{
Graphics g;
if (GtkToolkit.useGraphics2D ())
g = new GdkGraphics2D (this);
else
g = new GdkGraphics (this);
g.translate (-insets.left, -insets.top);
return g;
}
protected void postMouseEvent(int id, long when, int mods, int x, int y,
int clickCount, boolean popupTrigger)
{
super.postMouseEvent (id, when, mods,
x + insets.left, y + insets.top,
clickCount, popupTrigger);
}
protected void postExposeEvent (int x, int y, int width, int height)
{
if (!isInRepaint)
q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
new Rectangle (x + insets.left,
y + insets.top,
width, height)));
}
void create ()
{

View file

@ -41,6 +41,7 @@ package gnu.java.awt.peer.gtk;
import java.awt.Dialog;
import java.awt.FileDialog;
import java.awt.Graphics;
import java.awt.event.PaintEvent;
import java.awt.peer.FileDialogPeer;
import java.io.File;
import java.io.FilenameFilter;
@ -166,10 +167,10 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer
return filter.accept(dir, filename);
}
public Graphics getGraphics ()
// Sun does not call FileDialog.update.
protected void updateComponent (PaintEvent event)
{
// GtkFileDialog will repaint by itself
return null;
// Override GtkComponetPeer.updateComponent to do nothing.
}
// called back by native side: handle_response_cb

View file

@ -1,225 +0,0 @@
/* GtkFontPeer.java -- Implements FontPeer with GTK+
Copyright (C) 1999, 2004, 2005 Free Software Foundation, Inc.
This file is part of GNU Classpath.
GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package gnu.java.awt.peer.gtk;
import gnu.java.awt.peer.ClasspathFontPeer;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.awt.geom.Rectangle2D;
import java.text.CharacterIterator;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
public class GtkFontPeer extends ClasspathFontPeer
{
private static ResourceBundle bundle;
static
{
try
{
bundle = ResourceBundle.getBundle ("gnu.java.awt.peer.gtk.font");
}
catch (Throwable ignored)
{
bundle = null;
}
}
private final String Xname;
public GtkFontPeer (String name, int style)
{
// All fonts get a default size of 12 if size is not specified.
this(name, style, 12);
}
public GtkFontPeer (String name, int style, int size)
{
super(name, style, size);
String Xname = null;
if (bundle != null)
{
try
{
Xname = bundle.getString (name.toLowerCase () + "." + style);
}
catch (MissingResourceException mre)
{
// ignored
}
}
if (Xname == null)
{
String weight;
String slant;
String spacing;
if (style == Font.ITALIC || (style == (Font.BOLD+Font.ITALIC)))
slant = "i";
else
slant = "r";
if (style == Font.BOLD || (style == (Font.BOLD+Font.ITALIC)))
weight = "bold";
else
weight = "medium";
if (name.equals("Serif") || name.equals("SansSerif")
|| name.equals("Helvetica") || name.equals("Times"))
spacing = "p";
else
spacing = "c";
Xname = "-*-*-" + weight + "-" + slant + "-normal-*-*-" + size + "-*-*-" + spacing + "-*-*-*";
}
this.Xname = Xname;
}
public String getXLFD ()
{
return Xname;
}
/* remaining methods are for static compatibility with the newer
ClasspathFontPeer superclass; none of these methods ever existed or
worked on the older FontPeer interface, but we need to pretend to
support them anyways. */
public boolean canDisplay (Font font, char c)
{
throw new UnsupportedOperationException();
}
public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit)
{
throw new UnsupportedOperationException();
}
public String getSubFamilyName (Font font, Locale locale)
{
throw new UnsupportedOperationException();
}
public String getPostScriptName (Font font)
{
throw new UnsupportedOperationException();
}
public int getNumGlyphs (Font font)
{
throw new UnsupportedOperationException();
}
public int getMissingGlyphCode (Font font)
{
throw new UnsupportedOperationException();
}
public byte getBaselineFor (Font font, char c)
{
throw new UnsupportedOperationException();
}
public String getGlyphName (Font font, int glyphIndex)
{
throw new UnsupportedOperationException();
}
public GlyphVector createGlyphVector (Font font,
FontRenderContext frc,
CharacterIterator ci)
{
throw new UnsupportedOperationException();
}
public GlyphVector createGlyphVector (Font font,
FontRenderContext ctx,
int[] glyphCodes)
{
throw new UnsupportedOperationException();
}
public GlyphVector layoutGlyphVector (Font font,
FontRenderContext frc,
char[] chars, int start,
int limit, int flags)
{
throw new UnsupportedOperationException();
}
public FontMetrics getFontMetrics (Font font)
{
throw new UnsupportedOperationException();
}
public boolean hasUniformLineMetrics (Font font)
{
throw new UnsupportedOperationException();
}
public LineMetrics getLineMetrics (Font font,
CharacterIterator ci,
int begin, int limit,
FontRenderContext rc)
{
throw new UnsupportedOperationException();
}
public Rectangle2D getMaxCharBounds (Font font,
FontRenderContext rc)
{
throw new UnsupportedOperationException();
}
public Rectangle2D getStringBounds (Font font,
CharacterIterator ci,
int begin, int limit,
FontRenderContext frc)
{
throw new UnsupportedOperationException();
}
}

View file

@ -1,5 +1,5 @@
/* GtkFramePeer.java -- Implements FramePeer with GTK
Copyright (C) 1999, 2002, 2004 Free Software Foundation, Inc.
Copyright (C) 1999, 2002, 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -122,25 +122,11 @@ public class GtkFramePeer extends GtkWindowPeer
public void setBounds (int x, int y, int width, int height)
{
// prevent window_configure_cb -> awtComponent.setSize ->
// peer.setBounds -> nativeSetBounds self-deadlock on GDK lock.
if (Thread.currentThread() == GtkToolkit.mainThread)
{
int menuBarWidth = width - insets.left - insets.right;
if (menuBar != null && menuBarWidth > 0)
setMenuBarWidthUnlocked (menuBar, menuBarWidth);
return;
}
int menuBarWidth = width - insets.left - insets.right;
if (menuBar != null && menuBarWidth > 0)
setMenuBarWidth (menuBar, menuBarWidth);
nativeSetBounds (x, y,
width - insets.left - insets.right,
height - insets.top - insets.bottom
+ menuBarHeight);
super.setBounds(x, y, width, height + menuBarHeight);
}
public void setResizable (boolean resizable)
@ -196,56 +182,21 @@ public class GtkFramePeer extends GtkWindowPeer
}
}
public Graphics getGraphics ()
{
Graphics g;
if (GtkToolkit.useGraphics2D ())
g = new GdkGraphics2D (this);
else
g = new GdkGraphics (this);
g.translate (-insets.left, -insets.top);
return g;
}
protected void postConfigureEvent (int x, int y, int width, int height)
{
int frame_width = width + insets.left + insets.right;
if (menuBar != null && width > 0)
setMenuBarWidthUnlocked (menuBar, width);
// Since insets.top already includes the MenuBar's height, we need
// to subtract the MenuBar's height from the top inset.
int frame_height = height + insets.top + insets.bottom - menuBarHeight;
int frame_height = height - menuBarHeight;
if (frame_width != awtComponent.getWidth()
|| frame_height != awtComponent.getHeight())
awtComponent.setSize(frame_width, frame_height);
int frame_x = x - insets.left;
// Likewise, since insets.top includes the MenuBar height, we need
// to add back the MenuBar height to the frame's y position. If
// no MenuBar exists in this frame, the MenuBar height will be 0.
int frame_y = y - insets.top + menuBarHeight;
int frame_y = y + menuBarHeight;
if (frame_x != awtComponent.getX()
|| frame_y != awtComponent.getY())
{
// awtComponent.setLocation(frame_x, frame_y);
}
}
protected void postMouseEvent(int id, long when, int mods, int x, int y,
int clickCount, boolean popupTrigger)
{
super.postMouseEvent (id, when, mods,
x + insets.left, y + insets.top,
clickCount, popupTrigger);
}
protected void postExposeEvent (int x, int y, int width, int height)
{
if (!isInRepaint)
q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
new Rectangle (x + insets.left,
y + insets.top,
width, height)));
super.postConfigureEvent(x, frame_y, width, frame_height);
}
public int getState ()

View file

@ -123,41 +123,50 @@ public class GtkImage extends Image
/**
* Returns a copy of the pixel data as a java array.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native int[] getPixels();
/**
* Sets the pixel data from a java array.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native void setPixels(int[] pixels);
/**
* Loads an image using gdk-pixbuf from a file.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native boolean loadPixbuf(String name);
/**
* Loads an image using gdk-pixbuf from data.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native boolean loadImageFromData(byte[] data);
/**
* Allocates a Gtk Pixbuf or pixmap
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native void createPixmap();
/**
* Frees the above.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native void freePixmap();
/**
* Sets the pixmap to scaled copy of src image. hints are rendering hints.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native void createScaledPixmap(GtkImage src, int hints);
/**
* Draws the image, optionally scaled and composited.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
* Also acquires global gdk lock for drawing.
*/
private native void drawPixelsScaled (GdkGraphics gc,
int bg_red, int bg_green, int bg_blue,
@ -166,6 +175,8 @@ public class GtkImage extends Image
/**
* Draws the image, optionally scaled flipped and composited.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
* Also acquires global gdk lock for drawing.
*/
private native void drawPixelsScaledFlipped (GdkGraphics gc,
int bg_red, int bg_green,
@ -219,12 +230,21 @@ public class GtkImage extends Image
File f = new File(filename);
try
{
if (loadPixbuf(f.getCanonicalPath()) != true)
throw new IllegalArgumentException("Couldn't load image: "+filename);
String path = f.getCanonicalPath();
synchronized(GdkPixbufDecoder.pixbufLock)
{
if (loadPixbuf(f.getCanonicalPath()) != true)
throw new IllegalArgumentException("Couldn't load image: "
+ filename);
}
}
catch(IOException e)
{
throw new IllegalArgumentException("Couldn't load image: "+filename);
IllegalArgumentException iae;
iae = new IllegalArgumentException("Couldn't load image: "
+ filename);
iae.initCause(e);
throw iae;
}
isLoaded = true;
@ -241,8 +261,11 @@ public class GtkImage extends Image
*/
public GtkImage (byte[] data)
{
if (loadImageFromData (data) != true)
throw new IllegalArgumentException ("Couldn't load image.");
synchronized(GdkPixbufDecoder.pixbufLock)
{
if (loadImageFromData (data) != true)
throw new IllegalArgumentException ("Couldn't load image.");
}
isLoaded = true;
observers = null;
@ -277,8 +300,12 @@ public class GtkImage extends Image
{
throw new IllegalArgumentException ("Couldn't load image.");
}
if (loadImageFromData (baos.toByteArray()) != true)
throw new IllegalArgumentException ("Couldn't load image.");
byte[] array = baos.toByteArray();
synchronized(GdkPixbufDecoder.pixbufLock)
{
if (loadImageFromData(array) != true)
throw new IllegalArgumentException ("Couldn't load image.");
}
isLoaded = true;
observers = null;
@ -296,7 +323,10 @@ public class GtkImage extends Image
isLoaded = true;
observers = null;
offScreen = true;
createPixmap();
synchronized(GdkPixbufDecoder.pixbufLock)
{
createPixmap();
}
}
/**
@ -312,7 +342,10 @@ public class GtkImage extends Image
offScreen = false;
// Use the GDK scaling method.
createScaledPixmap(src, hints);
synchronized(GdkPixbufDecoder.pixbufLock)
{
createScaledPixmap(src, hints);
}
}
/**
@ -322,7 +355,10 @@ public class GtkImage extends Image
GtkImage (Pointer pixbuf)
{
pixmap = pixbuf;
createFromPixbuf();
synchronized(GdkPixbufDecoder.pixbufLock)
{
createFromPixbuf();
}
isLoaded = true;
observers = null;
offScreen = false;
@ -349,6 +385,7 @@ public class GtkImage extends Image
/**
* Native helper function for constructor that takes a pixbuf Pointer.
* Should be called with the GdkPixbufDecoder.pixbufLock held.
*/
private native void createFromPixbuf();
@ -370,8 +407,11 @@ public class GtkImage extends Image
isLoaded = true;
deliver();
createPixmap();
setPixels(pixels);
synchronized(GdkPixbufDecoder.pixbufLock)
{
createPixmap();
setPixels(pixels);
}
}
// java.awt.Image methods ////////////////////////////////////////////////
@ -408,7 +448,13 @@ public class GtkImage extends Image
{
if (!isLoaded)
return null;
return new MemoryImageSource(width, height, nativeModel, getPixels(),
int[] pixels;
synchronized(GdkPixbufDecoder.pixbufLock)
{
pixels = getPixels();
}
return new MemoryImageSource(width, height, nativeModel, pixels,
0, width);
}
@ -454,7 +500,10 @@ public class GtkImage extends Image
{
observers = new Vector();
isLoaded = false;
freePixmap();
synchronized(GdkPixbufDecoder.pixbufLock)
{
freePixmap();
}
source.startProduction(new GtkImageConsumer(this, source));
}
}
@ -462,7 +511,12 @@ public class GtkImage extends Image
public void finalize()
{
if (isLoaded)
freePixmap();
{
synchronized(GdkPixbufDecoder.pixbufLock)
{
freePixmap();
}
}
}
/**
@ -529,23 +583,29 @@ public class GtkImage extends Image
srcHeight = height - srcY;
}
if ( this.width <= 0 || this.height <= 0 )
return true;
if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0)
return true;
if(bgcolor != null)
drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (),
bgcolor.getBlue (),
flipX, flipY,
srcX, srcY,
srcWidth, srcHeight,
dstX, dstY,
dstWidth, dstHeight,
true);
else
drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY,
srcX, srcY, srcWidth, srcHeight,
dstX, dstY, dstWidth, dstHeight,
false);
synchronized(GdkPixbufDecoder.pixbufLock)
{
if(bgcolor != null)
drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (),
bgcolor.getBlue (),
flipX, flipY,
srcX, srcY,
srcWidth, srcHeight,
dstX, dstY,
dstWidth, dstHeight,
true);
else
drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY,
srcX, srcY, srcWidth, srcHeight,
dstX, dstY, dstWidth, dstHeight,
false);
}
return true;
}
@ -559,11 +619,17 @@ public class GtkImage extends Image
if (addObserver(observer))
return false;
if(bgcolor != null)
drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (),
bgcolor.getBlue (), x, y, width, height, true);
else
drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false);
if ( this.width <= 0 || this.height <= 0 )
return true;
synchronized(GdkPixbufDecoder.pixbufLock)
{
if(bgcolor != null)
drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (),
bgcolor.getBlue (), x, y, width, height, true);
else
drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false);
}
return true;
}

View file

@ -40,6 +40,7 @@ package gnu.java.awt.peer.gtk;
import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.List;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
@ -120,11 +121,12 @@ public class GtkListPeer extends GtkComponentPeer
public Dimension preferredSize (int rows)
{
int dims[] = new int[2];
int visibleRows = ((List) awtComponent).getRows();
getSize (rows, visibleRows, dims);
return new Dimension (dims[0], dims[1]);
// getSize returns the minimum size of the list.
// The width is too narrow for a typical list.
List l = (List) awtComponent;
Dimension d = getMinimumSize();
FontMetrics fm = l.getFontMetrics(l.getFont());
return new Dimension(d.width + fm.stringWidth("1234567890"), d.height);
}
public void removeAll ()

View file

@ -39,9 +39,7 @@ exception statement from your version. */
package gnu.java.awt.peer.gtk;
import java.awt.AWTEvent;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.PaintEvent;
import java.awt.peer.PanelPeer;
@ -59,35 +57,10 @@ public class GtkPanelPeer extends GtkContainerPeer
public void handleEvent(AWTEvent event)
{
int id = event.getID();
switch (id)
{
case MouseEvent.MOUSE_PRESSED:
awtComponent.requestFocusInWindow();
break;
case PaintEvent.UPDATE:
case PaintEvent.PAINT:
{
try
{
Graphics g = getGraphics();
if (! awtComponent.isShowing() || awtComponent.getWidth() < 1
|| awtComponent.getHeight() < 1 || g == null)
return;
g.setClip(((PaintEvent) event).getUpdateRect());
// Do not want to clear anything before painting.);
awtComponent.paint(g);
g.dispose();
return;
}
catch (InternalError e)
{
System.err.println(e);
}
}
}
if (id == MouseEvent.MOUSE_PRESSED)
awtComponent.requestFocusInWindow();
super.handleEvent(event);
}

View file

@ -55,9 +55,6 @@ import java.awt.Image;
* that the available flavors might have changed. When requested it
* (lazily) caches the targets, and (text, image, or files/uris)
* clipboard contents.
*
* XXX - should only cache when
* gdk_display_supports_selection_notification is true.
*/
public class GtkSelection implements Transferable
{
@ -66,6 +63,11 @@ public class GtkSelection implements Transferable
*/
static private Object requestLock = new Object();
/**
* Whether we belong to the Clipboard (true) or to the Primary selection.
*/
private final boolean clipboard;
/**
* Whether a request for mimetypes, text, images, uris or byte[] is
* currently in progress. Should only be tested or set with
@ -143,10 +145,13 @@ public class GtkSelection implements Transferable
private byte[] bytes;
/**
* Should only be created by the GtkClipboard class.
* Should only be created by the GtkClipboard class. The clipboard
* should be either GtkClipboard.clipboard or
* GtkClipboard.selection.
*/
GtkSelection()
GtkSelection(GtkClipboard clipboard)
{
this.clipboard = (clipboard == GtkClipboard.clipboard);
}
/**
@ -181,7 +186,7 @@ public class GtkSelection implements Transferable
if (! mimeTypesDelivered)
{
requestInProgress = true;
requestMimeTypes();
requestMimeTypes(clipboard);
while (! mimeTypesDelivered)
{
try
@ -312,7 +317,7 @@ public class GtkSelection implements Transferable
if (! textDelivered)
{
requestInProgress = true;
requestText();
requestText(clipboard);
while (! textDelivered)
{
try
@ -385,7 +390,7 @@ public class GtkSelection implements Transferable
if (! imageDelivered)
{
requestInProgress = true;
requestImage();
requestImage(clipboard);
while (! imageDelivered)
{
try
@ -464,7 +469,7 @@ public class GtkSelection implements Transferable
if (! urisDelivered)
{
requestInProgress = true;
requestURIs();
requestURIs(clipboard);
while (! urisDelivered)
{
try
@ -547,7 +552,7 @@ public class GtkSelection implements Transferable
// Request bytes and wait till they are available.
requestInProgress = true;
requestBytes(target);
requestBytes(clipboard, target);
while (! bytesDelivered)
{
try
@ -653,12 +658,14 @@ public class GtkSelection implements Transferable
* content is available the contentLock will be notified through
* textAvailable, imageAvailable, urisAvailable or bytesAvailable and the
* appropriate field is set.
* The clipboard argument is true if we want the Clipboard, and false
* if we want the (primary) selection.
*/
private native void requestText();
private native void requestImage();
private native void requestURIs();
private native void requestBytes(String target);
private native void requestText(boolean clipboard);
private native void requestImage(boolean clipboard);
private native void requestURIs(boolean clipboard);
private native void requestBytes(boolean clipboard, String target);
/* Similar to the above but for requesting the supported targets. */
private native void requestMimeTypes();
private native void requestMimeTypes(boolean clipboard);
}

View file

@ -361,7 +361,16 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
if (secman != null)
secman.checkSystemClipboardAccess();
return GtkClipboard.getInstance();
return GtkClipboard.getClipboardInstance();
}
public Clipboard getSystemSelection()
{
SecurityManager secman = System.getSecurityManager();
if (secman != null)
secman.checkSystemClipboardAccess();
return GtkClipboard.getSelectionInstance();
}
/**
@ -570,6 +579,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
return q;
}
public Cursor createCustomCursor(Image image, Point hotspot, String name)
{
return new GtkCursor(image, hotspot, name);
}
protected native void loadSystemColors (int[] systemColors);
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)

View file

@ -1,5 +1,5 @@
/* GtkWindowPeer.java -- Implements WindowPeer with GTK
Copyright (C) 1998, 1999, 2002, 2005 Free Software Foundation, Inc.
Copyright (C) 1998, 1999, 2002, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -42,7 +42,9 @@ import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.PaintEvent;
import java.awt.event.WindowEvent;
import java.awt.peer.WindowPeer;
@ -62,20 +64,37 @@ public class GtkWindowPeer extends GtkContainerPeer
private boolean hasBeenShown = false;
private int oldState = Frame.NORMAL;
// Cached awt window component location, width and height.
private int x, y, width, height;
native void gtkWindowSetTitle (String title);
native void gtkWindowSetResizable (boolean resizable);
native void gtkWindowSetModal (boolean modal);
native void realize ();
int getWidth ()
/** Returns the cached width of the AWT window component. */
int getX ()
{
return awtComponent.getWidth();
return x;
}
/** Returns the cached width of the AWT window component. */
int getY ()
{
return y;
}
/** Returns the cached width of the AWT window component. */
int getWidth ()
{
return width;
}
/** Returns the cached height of the AWT window component. */
int getHeight ()
{
return awtComponent.getHeight();
return height;
}
native void create (int type, boolean decorated, GtkWindowPeer parent);
@ -85,6 +104,10 @@ public class GtkWindowPeer extends GtkContainerPeer
Window window = (Window) awtComponent;
GtkWindowPeer parent_peer = null;
Component parent = awtComponent.getParent();
x = awtComponent.getX();
y = awtComponent.getY();
height = awtComponent.getHeight();
width = awtComponent.getWidth();
if (!window.isFocusableWindow())
type = GDK_WINDOW_TYPE_HINT_MENU;
@ -129,37 +152,28 @@ public class GtkWindowPeer extends GtkContainerPeer
native void nativeSetLocation (int x, int y);
native void nativeSetLocationUnlocked (int x, int y);
public void setLocation (int x, int y)
// Called from show.
protected void setLocation (int x, int y)
{
// prevent window_configure_cb -> awtComponent.setSize ->
// peer.setBounds -> nativeSetBounds self-deadlock on GDK lock.
if (Thread.currentThread() == GtkToolkit.mainThread)
return;
nativeSetLocation (x, y);
}
public void setLocationUnlocked (int x, int y)
{
nativeSetLocationUnlocked (x, y);
}
public void setBounds (int x, int y, int width, int height)
{
// prevent window_configure_cb -> awtComponent.setSize ->
// peer.setBounds -> nativeSetBounds self-deadlock on GDK lock.
if (Thread.currentThread() == GtkToolkit.mainThread)
return;
nativeSetBounds (x, y,
width - insets.left - insets.right,
height - insets.top - insets.bottom);
}
public void setBoundsUnlocked (int x, int y, int width, int height)
{
nativeSetBoundsUnlocked (x, y,
width - insets.left - insets.right,
height - insets.top - insets.bottom);
if (x != getX()
|| y != getY()
|| width != getWidth()
|| height != getHeight())
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
nativeSetBounds (x, y,
width - insets.left - insets.right,
height - insets.top - insets.bottom);
}
}
public void setTitle (String title)
@ -167,15 +181,25 @@ public class GtkWindowPeer extends GtkContainerPeer
gtkWindowSetTitle (title);
}
native void setSize (int width, int height);
// Called from setResizable
protected native void setSize (int width, int height);
/**
* Needed by both GtkFramePeer and GtkDialogPeer subclasses, so
* implemented here. But never actually called on a GtkWindowPeer
* itself.
*/
public void setResizable (boolean resizable)
{
// Call setSize; otherwise when resizable is changed from true to
// false the window will shrink to the dimensions it had before it
// was resizable.
setSize (awtComponent.getWidth() - insets.left - insets.right,
awtComponent.getHeight() - insets.top - insets.bottom);
x = awtComponent.getX();
y = awtComponent.getY();
width = awtComponent.getWidth();
height = awtComponent.getHeight();
setSize (width - insets.left - insets.right,
height - insets.top - insets.bottom);
gtkWindowSetResizable (resizable);
}
@ -195,23 +219,35 @@ public class GtkWindowPeer extends GtkContainerPeer
int frame_width = width + insets.left + insets.right;
int frame_height = height + insets.top + insets.bottom;
if (frame_width != awtComponent.getWidth()
|| frame_height != awtComponent.getHeight())
awtComponent.setSize(frame_width, frame_height);
if (frame_width != getWidth()
|| frame_height != getHeight())
{
this.width = frame_width;
this.height = frame_height;
q().postEvent(new ComponentEvent(awtComponent,
ComponentEvent.COMPONENT_RESIZED));
}
int frame_x = x - insets.left;
int frame_y = y - insets.top;
if (frame_x != awtComponent.getX()
|| frame_y != awtComponent.getY())
if (frame_x != getX()
|| frame_y != getY())
{
// awtComponent.setLocation(frame_x, frame_y);
this.x = frame_x;
this.y = frame_y;
q().postEvent(new ComponentEvent(awtComponent,
ComponentEvent.COMPONENT_MOVED));
}
}
public void show ()
{
setLocation(awtComponent.getX(), awtComponent.getY());
x = awtComponent.getX();
y = awtComponent.getY();
width = awtComponent.getWidth();
height = awtComponent.getHeight();
setLocation(x, y);
setVisible (true);
}
@ -244,37 +280,62 @@ public class GtkWindowPeer extends GtkContainerPeer
// TODO Auto-generated method stub
}
protected void postExposeEvent (int x, int y, int width, int height)
{
// Translate GTK co-ordinates, which do not include a window
// frame's insets, to AWT co-ordinates, which do include a window
// frame's insets. GtkWindowPeer should always have all-zero
// insets but GtkFramePeer and GtkDialogPeer insets will be
// non-zero.
q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT,
new Rectangle (x + insets.left,
y + insets.top,
width, height)));
}
public boolean requestWindowFocus()
{
// TODO Auto-generated method stub
return false;
}
public void handleEvent(AWTEvent event)
public Graphics getGraphics ()
{
int id = event.getID();
if (id == PaintEvent.UPDATE || id == PaintEvent.PAINT)
{
try
{
Graphics g = getGraphics();
if (! awtComponent.isShowing() || awtComponent.getWidth() < 1
|| awtComponent.getHeight() < 1 || g == null)
return;
Graphics g = super.getGraphics ();
// Translate AWT co-ordinates, which include a window frame's
// insets, to GTK co-ordinates, which do not include a window
// frame's insets. GtkWindowPeer should always have all-zero
// insets but GtkFramePeer and GtkDialogPeer insets will be
// non-zero.
g.translate (-insets.left, -insets.top);
return g;
}
g.setClip(((PaintEvent) event).getUpdateRect());
protected void updateComponent (PaintEvent event)
{
// Do not clear anything before painting. Sun never calls
// Window.update, only Window.paint.
paintComponent(event);
}
// Do not want to clear anything before painting.
awtComponent.paint(g);
protected void postMouseEvent(int id, long when, int mods, int x, int y,
int clickCount, boolean popupTrigger)
{
// Translate AWT co-ordinates, which include a window frame's
// insets, to GTK co-ordinates, which do not include a window
// frame's insets. GtkWindowPeer should always have all-zero
// insets but GtkFramePeer and GtkDialogPeer insets will be
// non-zero.
super.postMouseEvent (id, when, mods,
x + insets.left, y + insets.top,
clickCount, popupTrigger);
}
g.dispose();
return;
}
catch (InternalError e)
{
System.err.println(e);
}
}
super.handleEvent(event);
// We override this to keep it in sync with our internal
// representation.
public Rectangle getBounds()
{
return new Rectangle(x, y, width, height);
}
}

View file

@ -590,8 +590,7 @@ public class SwingComponentPeer
*/
public void setBounds(int x, int y, int width, int height)
{
if (swingComponent != null)
swingComponent.getJComponent().setBounds(x, y, width, height);
reshape(x, y, width, height);
}
/**

View file

@ -61,7 +61,7 @@ public class SwingContainerPeer
*
* @param awtCont
*/
public SwingContainerPeer(Container awtCont)
public SwingContainerPeer(Component awtCont)
{
init(awtCont, null);
}
@ -92,12 +92,7 @@ public class SwingContainerPeer
*/
public Insets getInsets()
{
Insets retVal;
if (swingComponent != null)
retVal = swingComponent.getJComponent().getInsets();
else
retVal = new Insets(0, 0, 0, 0);
return retVal;
return insets();
}
/**
@ -214,12 +209,15 @@ public class SwingContainerPeer
protected void handleMouseEvent(MouseEvent ev)
{
Component comp = awtComponent.getComponentAt(ev.getPoint());
ComponentPeer peer = comp.getPeer();
if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
if (comp != null)
{
ev.translatePoint(comp.getX(), comp.getY());
ev.setSource(comp);
((SwingComponentPeer) peer).handleMouseEvent(ev);
ComponentPeer peer = comp.getPeer();
if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
{
ev.translatePoint(comp.getX(), comp.getY());
ev.setSource(comp);
((SwingComponentPeer) peer).handleMouseEvent(ev);
}
}
}
@ -231,11 +229,14 @@ public class SwingContainerPeer
protected void handleMouseMotionEvent(MouseEvent ev)
{
Component comp = awtComponent.getComponentAt(ev.getPoint());
ComponentPeer peer = comp.getPeer();
if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
if (comp != null)
{
ev.translatePoint(comp.getX(), comp.getY());
((SwingComponentPeer) peer).handleMouseMotionEvent(ev);
ComponentPeer peer = comp.getPeer();
if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
{
ev.translatePoint(comp.getX(), comp.getY());
((SwingComponentPeer) peer).handleMouseMotionEvent(ev);
}
}
}
}