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

View file

@ -1,75 +0,0 @@
# This property file contains dependencies of classes, methods, and
# field on other methods or classes.
#
# Syntax:
#
# <used>: <needed 1> [... <needed N>]
#
# means that when <used> is included, <needed 1> (... <needed N>) must
# be included as well.
#
# <needed X> and <used> are of the form
#
# <class.methodOrField(signature)>
#
# or just
#
# <class>
#
# Within dependencies, variables can be used. A variable is defined as
# follows:
#
# {variable}: value1 value2 ... value<n>
#
# variables can be used on the right side of dependencies as follows:
#
# <used>: com.bla.blu.{variable}.Class.m()V
#
# The use of the variable will expand to <n> dependencies of the form
#
# <used>: com.bla.blu.value1.Class.m()V
# <used>: com.bla.blu.value2.Class.m()V
# ...
# <used>: com.bla.blu.value<n>.Class.m()V
#
# Variables can be redefined when building a system to select the
# required support for features like encodings, protocols, etc.
#
# Hints:
#
# - For methods and fields, the signature is mandatory. For
# specification, please see the Java Virtual Machine Specification by
# SUN. Unlike in the spec, field signatures (types) are in brackets.
#
# - Package names must be separated by '/' (and not '.'). E.g.,
# java/lang/Class (this is necessary, because the '.' is used to
# separate method or field names from classes)
#
# - In case <needed> refers to a class, only the class itself will be
# included in the resulting binary, NOT necessarily all its methods
# and fields. If you want to refer to all methods and fields, you can
# write class.* as an abbreviation.
#
# - Abbreviations for packages are also possible: my/package/* means all
# methods and fields of all classes in my/package.
#
# - A line with a trailing '\' continues in the next line.
# All encodings supported are loaded via gnu/java/io/EncodingManager.findEncoderConstructor
# or gnu/java/io/EncodingManager.findDecoderConstructor from class
# gnu/java/io/decode/Decoder<encoding>.
#
# This introduces a dependency for all encodings. To allow an easy selection
# and addition of encodings, the library variable {encodings} can be set to
# the set of supported encodings.
#
{encodings}: 8859_1 8859_2 8859_3 8859_4 8859_5 UTF8
gnu/java/io/EncodingManager.findEncoderConstructor(Ljava/lang/String;Z)Ljava/lang/reflect/Constructor;: \
gnu/java/io/decode/Decoder{encodings}.*
gnu/java/io/EncodingManager.findDecoderConstructor(Ljava/lang/String;Z)Ljava/lang/reflect/Constructor;: \
gnu/java/io/encode/Encoder{encodings}.* \
# end of file

View file

@ -81,6 +81,34 @@ public class ClassHelper
return name.substring(lastInd + 1);
}
/**
* Return the name of the class as written by the user.
* This is used by the various reflection toString methods.
* It differs from {@link Class#getName()} in that it prints
* arrays with trailing "[]"s. Note that it does not treat
* member classes specially, so a dollar sign may still appear
* in the result. This is intentional.
* @param klass the class
* @return a pretty form of the class' name
*/
public static String getUserName(Class klass)
{
int arrayCount = 0;
while (klass.isArray())
{
++arrayCount;
klass = klass.getComponentType();
}
String name = klass.getName();
if (arrayCount == 0)
return name;
StringBuilder b = new StringBuilder(name.length() + 2 * arrayCount);
b.append(name);
for (int i = 0; i < arrayCount; ++i)
b.append("[]");
return b.toString();
}
/** Cache of methods found in getAllMethods(). */
private static Map allMethods = new HashMap();

View file

@ -0,0 +1,243 @@
/* InstrumentationImpl.java -- GNU implementation of
java.lang.instrument.Instrumentation
Copyright (C) 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.lang;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Iterator;
/**
* An Instrumentation object has transformers that will
* be called each time a class is defined or redefined.
* The object is given to a <code>premain</code> function
* that is called before the <code>main</code> function.
*
* @author Nicolas Geoffray (nicolas.geoffray@menlina.com)
* @since 1.5
*/
public final class InstrumentationImpl implements Instrumentation
{
/* List of transformers */
/* FIXME[GENERICS]: Should be ClassFileTransformer list */
private ArrayList transformers = new ArrayList();
private InstrumentationImpl()
{
}
/**
* Adds a <code>ClassFileTransformer</class> object
* to the instrumentation. Each time a class is defined
* or redefined, the <code>transform</code> method of the
* <code>transformer</code> object is called.
*
* @param transformer the transformer to add
* @throws NullPointerException if transformer is null
*/
public void addTransformer(ClassFileTransformer transformer)
{
if (transformer == null)
throw new NullPointerException();
synchronized(transformers)
{
transformers.add(transformer);
}
}
/**
* Removes the given transformer from the set of transformers
* this Instrumentation object has.
*
* @param transformer the transformer to remove
* @return true if the transformer was found and removed, false if
* the transformer was not found
* @throws NullPointerException if transformer is null
*/
public boolean removeTransformer(ClassFileTransformer transformer)
{
if (transformer == null)
throw new NullPointerException();
boolean result;
synchronized (transformers)
{
result = transformers.remove(transformer);
}
return result;
}
/**
* Returns if the current JVM supports class redefinition
*
* @return true if the current JVM supports class redefinition
*/
public boolean isRedefineClassesSupported()
{
return VMInstrumentationImpl.isRedefineClassesSupported();
}
/**
* Redefine classes present in the definitions array, with
* the corresponding class files.
*
* @param definitions an array of classes to redefine
*
* @throws ClassNotFoundException if a class cannot be found
* @throws UnmodifiableClassException if a class cannot be modified
* @throws UnsupportedOperationException if the JVM does not support
* redefinition or the redefinition made unsupported changes
* @throws ClassFormatError if a class file is not valid
* @throws NoClassDefFoundError if a class name is not equal to the name
* in the class file specified
* @throws UnsupportedClassVersionError if the class file version numbers
* are unsupported
* @throws ClassCircularityError if circularity occured with the new
* classes
* @throws LinkageError if a linkage error occurs
* @throws NullPointerException if the definitions array is null, or any
* of its element
*
* @see isRedefineClassesSupported()
* @see addTransformer(java.lang.instrument.ClassFileTransformer)
* @see ClassFileTransformer
*/
public void redefineClasses(ClassDefinition[] definitions)
throws ClassNotFoundException,
UnmodifiableClassException
{
if (!isRedefineClassesSupported())
throw new UnsupportedOperationException();
VMInstrumentationImpl.redefineClasses(this, definitions);
}
/**
* Get all the classes loaded by the JVM.
*
* @return an array containing all the classes loaded by the JVM. The array
* is empty if no class is loaded.
*/
public Class[] getAllLoadedClasses()
{
return VMInstrumentationImpl.getAllLoadedClasses();
}
/**
* Get all the classes loaded by a given class loader
*
* @param loader the loader
*
* @return an array containing all the classes loaded by the given loader.
* The array is empty if no class was loaded by the loader.
*/
public Class[] getInitiatedClasses(ClassLoader loader)
{
return VMInstrumentationImpl.getInitiatedClasses(loader);
}
/**
* Get the size of an object.
*
* @param objectToSize the object
* @return the size of the object
* @throws NullPointerException if objectToSize is null.
*/
public long getObjectSize(Object objectToSize)
{
// We alleviate the VM work
if (objectToSize == null)
throw new NullPointerException();
return VMInstrumentationImpl.getObjectSize(objectToSize);
}
/**
* Called by the VM or redefineClasses to call each transformer
*
* @param loader the loader of the class
* @param className the name of the class with packages separated with "/"
* @param classBeingRedefined the class being redefined if it's the case,
* null otherwise
* @param protectionDomain the protection domain of the class being defined
* or redefined
* @param classfileBuffer the input byte buffer in class file format
*
* @return the new class file
*/
/* FIXME[GENERICS]: Should be Class<?> */
public byte[] callTransformers(ClassLoader loader, String className,
Class classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer)
{
byte[] newBuffer = null;
byte[] oldBuffer = classfileBuffer;
ClassFileTransformer current;
synchronized (transformers)
{
Iterator i = transformers.iterator();
while (i.hasNext())
{
/* FIXME[GENERICS]: Remove cast */
current = (ClassFileTransformer) i.next();
try
{
newBuffer = current.transform(loader, className,
classBeingRedefined, protectionDomain, oldBuffer);
}
catch (IllegalClassFormatException ignored)
{
//IGNORED
}
if (newBuffer != null)
oldBuffer = newBuffer;
}
}
return oldBuffer;
}
}

View file

@ -0,0 +1,92 @@
/* ClassSignatureParser.java
Copyright (C) 2005
Free Software Foundation
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.lang.reflect;
import java.lang.reflect.*;
import java.util.ArrayList;
public class ClassSignatureParser extends GenericSignatureParser
{
private TypeVariable[] typeParameters;
private Type superclassType;
private Type[] interfaceTypes;
public ClassSignatureParser(Class c, String signature)
{
super(c, c.getClassLoader(), signature);
if (peekChar() == '<')
{
typeParameters = readFormalTypeParameters();
}
else
{
typeParameters = new TypeVariable[0];
}
// SuperclassSignature
superclassType = readClassTypeSignature();
ArrayList interfaces = new ArrayList();
while (peekChar() == 'L')
{
// SuperinterfaceSignature
interfaces.add(readClassTypeSignature());
}
interfaceTypes = new Type[interfaces.size()];
interfaces.toArray(interfaceTypes);
end();
}
public TypeVariable[] getTypeParameters()
{
TypeImpl.resolve(typeParameters);
return typeParameters;
}
public Type getSuperclassType()
{
superclassType = TypeImpl.resolve(superclassType);
return superclassType;
}
public Type[] getInterfaceTypes()
{
TypeImpl.resolve(interfaceTypes);
return interfaceTypes;
}
}

View file

@ -0,0 +1,103 @@
/* FieldSignatureParser.java
Copyright (C) 2005
Free Software Foundation
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.lang.reflect;
import java.lang.reflect.GenericSignatureFormatError;
import java.lang.reflect.Type;
public final class FieldSignatureParser extends GenericSignatureParser
{
private Type type;
public FieldSignatureParser(Class container, String signature)
{
super(container, container.getClassLoader(), signature);
switch (peekChar())
{
case 'L':
case '[':
case 'T':
type = readFieldTypeSignature();
break;
case 'Z':
consume('Z');
type = boolean.class;
break;
case 'B':
consume('B');
type = byte.class;
break;
case 'S':
consume('S');
type = short.class;
break;
case 'C':
consume('C');
type = char.class;
break;
case 'I':
consume('I');
type = int.class;
break;
case 'F':
consume('F');
type = float.class;
break;
case 'J':
consume('J');
type = long.class;
break;
case 'D':
consume('D');
type = double.class;
break;
default:
throw new GenericSignatureFormatError();
}
end();
}
public Type getFieldType()
{
type = TypeImpl.resolve(type);
return type;
}
}

View file

@ -0,0 +1,622 @@
/* GenericSignatureParser.java
Copyright (C) 2005
Free Software Foundation
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.lang.reflect;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
final class TypeVariableImpl extends TypeImpl implements TypeVariable
{
private GenericDeclaration decl;
private Type[] bounds;
private String name;
TypeVariableImpl(GenericDeclaration decl, Type[] bounds, String name)
{
this.decl = decl;
this.bounds = bounds;
this.name = name;
}
Type resolve()
{
return this;
}
/* FIXME[GENERICS]: Remove cast */
public Type[] getBounds()
{
resolve(bounds);
return (Type[]) bounds.clone();
}
public GenericDeclaration getGenericDeclaration()
{
return decl;
}
public String getName()
{
return name;
}
public boolean equals(Object obj)
{
if (obj instanceof TypeVariableImpl)
{
TypeVariableImpl other = (TypeVariableImpl)obj;
return decl.equals(other.decl) && name.equals(other.name);
}
return false;
}
public int hashCode()
{
return 0x5f4d5156 ^ decl.hashCode() ^ name.hashCode();
}
public String toString()
{
return name;
}
}
final class ParameterizedTypeImpl extends TypeImpl implements ParameterizedType
{
private String rawTypeName;
private ClassLoader loader;
private Class rawType;
private Type owner;
private Type[] typeArgs;
ParameterizedTypeImpl(String rawTypeName, ClassLoader loader, Type owner,
Type[] typeArgs)
{
this.rawTypeName = rawTypeName;
this.loader = loader;
this.owner = owner;
this.typeArgs = typeArgs;
}
Type resolve()
{
if (rawType == null)
{
try
{
rawType = Class.forName(rawTypeName, false, loader);
}
catch (ClassNotFoundException x)
{
throw new TypeNotPresentException(rawTypeName, x);
}
}
if (typeArgs == null)
{
if (owner == null)
{
return rawType;
}
typeArgs = new Type[0];
}
resolve(typeArgs);
owner = resolve(owner);
return this;
}
/* FIXME[GENERICS]: Remove cast */
public Type[] getActualTypeArguments()
{
return (Type[]) typeArgs.clone();
}
public Type getRawType()
{
return rawType;
}
public Type getOwnerType()
{
return owner;
}
public boolean equals(Object obj)
{
if (obj instanceof ParameterizedTypeImpl)
{
ParameterizedTypeImpl other = (ParameterizedTypeImpl)obj;
return rawType.equals(other.rawType)
&& ((owner == null && other.owner == null)
|| owner.equals(other.owner))
&& Arrays.deepEquals(typeArgs, other.typeArgs);
}
return false;
}
public int hashCode()
{
int h = 0x58158970 ^ rawType.hashCode();
if (owner != null)
{
h ^= Integer.reverse(owner.hashCode());
}
for (int i = 0; i < typeArgs.length; i++)
{
h ^= Integer.rotateLeft(typeArgs[i].hashCode(), i);
}
return h;
}
public String toString()
{
StringBuilder sb = new StringBuilder();
if (owner != null)
{
sb.append(owner);
sb.append('.');
sb.append(rawType.getSimpleName());
}
else
{
sb.append(rawTypeName);
}
if (typeArgs.length > 0)
{
sb.append('<');
for (int i = 0; i < typeArgs.length; i++)
{
if (i > 0)
sb.append(", ");
if (typeArgs[i] instanceof Class)
{
sb.append(((Class)typeArgs[i]).getName());
}
else
{
sb.append(typeArgs[i]);
}
}
sb.append('>');
}
return sb.toString();
}
}
final class GenericArrayTypeImpl extends TypeImpl implements GenericArrayType
{
private Type componentType;
GenericArrayTypeImpl(Type componentType)
{
this.componentType = componentType;
}
Type resolve()
{
componentType = resolve(componentType);
return this;
}
public Type getGenericComponentType()
{
return componentType;
}
public boolean equals(Object obj)
{
if (obj instanceof GenericArrayTypeImpl)
{
GenericArrayTypeImpl other = (GenericArrayTypeImpl)obj;
return componentType.equals(other.componentType);
}
return false;
}
public int hashCode()
{
return 0x4be37a7f ^ componentType.hashCode();
}
public String toString()
{
return componentType + "[]";
}
}
final class UnresolvedTypeVariable extends TypeImpl implements Type
{
private GenericDeclaration decl;
private String name;
UnresolvedTypeVariable(GenericDeclaration decl, String name)
{
this.decl = decl;
this.name = name;
}
Type resolve()
{
GenericDeclaration d = decl;
while (d != null)
{
TypeVariable[] vars = d.getTypeParameters();
for (int a = 0; a < vars.length ; ++a)
{
if (vars[a].getName().equals(name))
{
return vars[a];
}
}
d = getParent(d);
}
throw new MalformedParameterizedTypeException();
}
private static GenericDeclaration getParent(GenericDeclaration d)
{
if (d instanceof Class)
{
Method m = ((Class)d).getEnclosingMethod();
if (m != null)
{
return m;
}
Constructor c = ((Class)d).getEnclosingConstructor();
if (c != null)
{
return c;
}
return ((Class)d).getEnclosingClass();
}
else if (d instanceof Method)
{
return ((Method)d).getDeclaringClass();
}
else if (d instanceof Constructor)
{
return ((Constructor)d).getDeclaringClass();
}
else
{
// TODO figure out what this represents
throw new Error();
}
}
}
final class WildcardTypeImpl extends TypeImpl implements WildcardType
{
private Type lower;
private Type upper;
WildcardTypeImpl(Type lower, Type upper)
{
this.lower = lower;
this.upper = upper;
}
Type resolve()
{
upper = resolve(upper);
lower = resolve(lower);
return this;
}
public Type[] getUpperBounds()
{
if (upper == null)
{
return new Type[0];
}
return new Type[] { upper };
}
public Type[] getLowerBounds()
{
if (lower == null)
{
return new Type[0];
}
return new Type[] { lower };
}
public boolean equals(Object obj)
{
if (obj instanceof WildcardTypeImpl)
{
WildcardTypeImpl other = (WildcardTypeImpl)obj;
return Arrays.deepEquals(getUpperBounds(), other.getUpperBounds())
&& Arrays.deepEquals(getLowerBounds(), other.getLowerBounds());
}
return false;
}
public int hashCode()
{
int h = 0x75d074fd;
if (upper != null)
{
h ^= upper.hashCode();
}
if (lower != null)
{
h ^= lower.hashCode();
}
return h;
}
public String toString()
{
if (lower != null)
{
return "? super " + lower;
}
if (upper == java.lang.Object.class)
{
return "?";
}
return "? extends " + upper;
}
}
class GenericSignatureParser
{
private ClassLoader loader;
private GenericDeclaration container;
private String signature;
private int pos;
GenericSignatureParser(GenericDeclaration container, ClassLoader loader,
String signature)
{
this.container = container;
this.loader = loader;
this.signature = signature;
}
TypeVariable[] readFormalTypeParameters()
{
consume('<');
ArrayList params = new ArrayList();
do
{
// TODO should we handle name clashes?
params.add(readFormalTypeParameter());
} while (peekChar() != '>');
consume('>');
TypeVariable[] list = new TypeVariable[params.size()];
params.toArray(list);
return list;
}
private TypeVariable readFormalTypeParameter()
{
String identifier = readIdentifier();
consume(':');
ArrayList bounds = new ArrayList();
if (peekChar() != ':')
{
bounds.add(readFieldTypeSignature());
}
while (peekChar() == ':')
{
consume(':');
bounds.add(readFieldTypeSignature());
}
Type[] b = new Type[bounds.size()];
bounds.toArray(b);
return new TypeVariableImpl(container, b, identifier);
}
Type readFieldTypeSignature()
{
switch (peekChar())
{
case 'L':
return readClassTypeSignature();
case '[':
return readArrayTypeSignature();
case 'T':
return readTypeVariableSignature();
default:
throw new GenericSignatureFormatError();
}
}
Type readClassTypeSignature()
{
consume('L');
String className = "";
for (;;)
{
String part = readIdentifier();
if (peekChar() != '/')
{
className += part;
break;
}
consume('/');
className += part + ".";
}
Type[] typeArguments = null;
if (peekChar() == '<')
{
typeArguments = readTypeArguments();
}
Type type = new ParameterizedTypeImpl(className, loader, null,
typeArguments);
while (peekChar() == '.')
{
consume('.');
className += "$" + readIdentifier();
typeArguments = null;
if (peekChar() == '<')
{
typeArguments = readTypeArguments();
}
type = new ParameterizedTypeImpl(className, loader, type,
typeArguments);
}
consume(';');
return type;
}
private Type[] readTypeArguments()
{
consume('<');
ArrayList list = new ArrayList();
do
{
list.add(readTypeArgument());
} while ((peekChar() != '>'));
consume('>');
Type[] arr = new Type[list.size()];
list.toArray(arr);
return arr;
}
private Type readTypeArgument()
{
char c = peekChar();
if (c == '+')
{
consume('+');
return new WildcardTypeImpl(null, readFieldTypeSignature());
}
else if (c == '-')
{
consume('-');
return new WildcardTypeImpl(readFieldTypeSignature(),
java.lang.Object.class);
}
else if (c == '*')
{
consume('*');
return new WildcardTypeImpl(null, java.lang.Object.class);
}
else
{
return readFieldTypeSignature();
}
}
Type readArrayTypeSignature()
{
consume('[');
switch (peekChar())
{
case 'L':
case '[':
case 'T':
return new GenericArrayTypeImpl(readFieldTypeSignature());
case 'Z':
consume('Z');
return boolean[].class;
case 'B':
consume('B');
return byte[].class;
case 'S':
consume('S');
return short[].class;
case 'C':
consume('C');
return char[].class;
case 'I':
consume('I');
return int[].class;
case 'F':
consume('F');
return float[].class;
case 'J':
consume('J');
return long[].class;
case 'D':
consume('D');
return double[].class;
default:
throw new GenericSignatureFormatError();
}
}
Type readTypeVariableSignature()
{
consume('T');
String identifier = readIdentifier();
consume(';');
return new UnresolvedTypeVariable(container, identifier);
}
private String readIdentifier()
{
int start = pos;
char c;
do
{
readChar();
c = peekChar();
} while (";:./<>-+*".indexOf(c) == -1);
return signature.substring(start, pos);
}
final char peekChar()
{
if (pos == signature.length())
return '\u0000';
else
return signature.charAt(pos);
}
final char readChar()
{
return signature.charAt(pos++);
}
final void consume(char c)
{
if (readChar() != c)
throw new GenericSignatureFormatError();
}
final void end()
{
if (pos != signature.length())
throw new GenericSignatureFormatError();
}
}

View file

@ -0,0 +1,167 @@
/* MethodSignatureParser.java
Copyright (C) 2005
Free Software Foundation
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.lang.reflect;
import java.lang.reflect.*;
import java.util.ArrayList;
public class MethodSignatureParser extends GenericSignatureParser
{
private TypeVariable[] typeParameters;
private Type[] argTypes;
private Type retType;
private Type[] throwsSigs;
public MethodSignatureParser(Method method, String signature)
{
this(method, method.getDeclaringClass().getClassLoader(), signature);
}
public MethodSignatureParser(Constructor method, String signature)
{
this(method, method.getDeclaringClass().getClassLoader(), signature);
}
private MethodSignatureParser(GenericDeclaration wrapper,
ClassLoader loader, String signature)
{
super(wrapper, loader, signature);
if (peekChar() == '<')
{
typeParameters = readFormalTypeParameters();
}
else
{
typeParameters = new TypeVariable[0];
}
consume('(');
ArrayList args = new ArrayList();
while (peekChar() != ')')
{
args.add(readTypeSignature());
}
argTypes = new Type[args.size()];
args.toArray(argTypes);
consume(')');
retType = readTypeSignature();
ArrayList throwsSigs = new ArrayList();
while (peekChar() == '^')
{
consume('^');
if(peekChar() == 'T')
{
throwsSigs.add(readTypeVariableSignature());
}
else
{
throwsSigs.add(readClassTypeSignature());
}
}
this.throwsSigs = new Type[throwsSigs.size()];
throwsSigs.toArray(this.throwsSigs);
end();
}
public TypeVariable[] getTypeParameters()
{
TypeImpl.resolve(typeParameters);
return typeParameters;
}
public Type[] getGenericParameterTypes()
{
TypeImpl.resolve(argTypes);
return argTypes;
}
public Type getGenericReturnType()
{
retType = TypeImpl.resolve(retType);
return retType;
}
public Type[] getGenericExceptionTypes()
{
TypeImpl.resolve(throwsSigs);
return throwsSigs;
}
private Type readTypeSignature()
{
switch (peekChar())
{
case 'T':
return readTypeVariableSignature();
case 'L':
return readClassTypeSignature();
case '[':
return readArrayTypeSignature();
case 'Z':
consume('Z');
return boolean.class;
case 'B':
consume('B');
return byte.class;
case 'S':
consume('S');
return short.class;
case 'C':
consume('C');
return char.class;
case 'I':
consume('I');
return int.class;
case 'F':
consume('F');
return float.class;
case 'J':
consume('J');
return long.class;
case 'D':
consume('D');
return double.class;
case 'V':
consume('V');
return void.class;
default:
throw new GenericSignatureFormatError();
}
}
}

View file

@ -0,0 +1,63 @@
/* TypeImpl.java
Copyright (C) 2005
Free Software Foundation
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.lang.reflect;
import java.lang.reflect.Type;
abstract class TypeImpl implements Type
{
abstract Type resolve();
static void resolve(Type[] types)
{
for (int i = 0; i < types.length; i++)
{
types[i] = resolve(types[i]);
}
}
static Type resolve(Type type)
{
if (type instanceof TypeImpl)
{
type = ((TypeImpl) type).resolve();
}
return type;
}
}

View file

@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.locale;
import java.text.Collator;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
@ -154,5 +155,57 @@ public class LocaleHelper
}
return localizedString;
}
/**
* Return an array of all the locales for which there is a
* {@link Collator} instance. A new array is returned each time.
*/
public static Locale[] getCollatorLocales()
{
// For now we don't bother caching. This is probably
// not called very frequently. And, we would have to
// clone the array anyway.
if (LocaleData.collatorLocaleNames.length == 0)
return new Locale[] { Locale.US };
Locale[] result = new Locale[LocaleData.collatorLocaleNames.length];
for (int i = 0; i < result.length; ++i)
{
String language;
String region = "";
String variant = "";
String name = LocaleData.collatorLocaleNames[i];
language = name.substring(0, 2);
if (name.length() > 2)
region = name.substring(3);
int index = region.indexOf("_");
if (index > 0)
{
variant = region.substring(index + 1);
region = region.substring(0, index - 1);
}
result[i] = new Locale(language, region, variant);
}
return result;
}
/**
* Return the number of locales we know of.
*/
public static int getLocaleCount()
{
return LocaleData.localeNames.length;
}
/**
* Return the Nth locale name.
*/
public static String getLocaleName(int n)
{
return LocaleData.localeNames[n];
}
}

View file

@ -0,0 +1,94 @@
/* DefaultContentHandlerFactory.java
Copyright (C) 2004 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.net;
import java.io.IOException;
import java.net.ContentHandler;
import java.net.ContentHandlerFactory;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.HashSet;
/** Content Handler for Image types, using the AWT Toolkit's image decoder. */
class ImageHandler extends ContentHandler
{
static ImageHandler instance = new ImageHandler();
public Object getContent(URLConnection urlc) throws IOException
{
// FIXME: implement using ImageIO
// ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit();
// java.awt.image.ImageProducer ip = tk.createImageProducer(urlc.getURL());
// return ip;
return null;
}
}
/**
*/
public class DefaultContentHandlerFactory implements ContentHandlerFactory
{
/** For now, hard code the list of types that we assume should
* be supported by the Toolkit. ClasspathToolkit should perhaps provide
* an API to express what Image MIME types the Toolkit understands.
*/
private static String[] known_image_types =
{
"image/bmp",
"image/gif",
"image/jpeg",
"image/png",
"image/tiff",
"image/x-portable-anymap",
"image/x-cmu-raster",
"image/x-xbitmap",
"image/x-xpixmap"
};
private static HashSet imageTypes
= new HashSet(Arrays.asList(known_image_types));
public ContentHandler createContentHandler(String mimeType)
{
if (imageTypes.contains(mimeType))
return ImageHandler.instance;
// Currently, only image types are handled.
return null;
}
}

View file

@ -0,0 +1,172 @@
/* LocalServerSocket.java -- a unix domain server socket.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a 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 of the License, 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; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, 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.net.local;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
public final class LocalServerSocket extends ServerSocket
{
// Fields.
// -------------------------------------------------------------------------
private LocalSocketImpl myImpl;
private boolean closed;
// Constructors.
// -------------------------------------------------------------------------
public LocalServerSocket () throws IOException
{
myImpl = new LocalSocketImpl ();
}
public LocalServerSocket (SocketAddress bindPoint) throws IOException
{
this ();
bind (bindPoint);
}
// Instance methods.
// -------------------------------------------------------------------------
public void bind (SocketAddress bindPoint) throws IOException
{
bind (bindPoint, 0);
}
public void bind (SocketAddress bindPoint, int backlog) throws IOException
{
myImpl.doCreate ();
myImpl.bind (bindPoint);
myImpl.listen (backlog);
}
public InetAddress getInetAddress ()
{
return null;
}
public int getLocalPort ()
{
return -1;
}
public SocketAddress getLocalSocketAddress ()
{
return myImpl.getLocalAddress ();
}
public Socket accept () throws IOException
{
LocalSocket s = new LocalSocket (true);
myImpl.accept (s.getLocalImpl());
s.localConnected = true;
return s;
}
public void close () throws IOException
{
myImpl.close ();
myImpl.unlink ();
closed = true;
}
public boolean isBound ()
{
return myImpl.getLocalAddress () != null;
}
public boolean isClosed ()
{
return closed;
}
public void setSoTimeout (int timeout)
{
throw new UnsupportedOperationException ("local sockets do not support timeouts");
}
public int getSoTimeout ()
{
throw new UnsupportedOperationException ("local sockets do not support timeouts");
}
public void setReuseAddress (boolean b)
{
throw new UnsupportedOperationException ("local sockets do not support reuse address");
}
public boolean getReuseAddress ()
{
throw new UnsupportedOperationException ("local sockets do not support reuse address");
}
public String toString ()
{
return LocalServerSocket.class.getName() + " [ address="
+ myImpl.getLocalAddress() + " ]";
}
public void setReceiveBufferSize (int size)
{
throw new UnsupportedOperationException ("local sockets do not support buffer size");
}
public int getReceiveBufferSize ()
{
throw new UnsupportedOperationException ("local sockets do not support buffer size");
}
public void setSendBufferSize (int size)
{
throw new UnsupportedOperationException ("local sockets do not support buffer size");
}
public int getSendBufferSize ()
{
throw new UnsupportedOperationException ("local sockets do not support buffer size");
}
}

View file

@ -0,0 +1,312 @@
/* LocalSocket.java -- a unix domain client socket.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a 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 of the License, 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; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, 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.net.local;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.nio.channels.IllegalBlockingModeException;
import java.nio.channels.SocketChannel;
/**
* A local, or unix-domain socket. Unix domain sockets are connected on the
* local filesystem itself, rather than a remote address.
*/
public final class LocalSocket extends Socket
{
// Fields.
// -------------------------------------------------------------------------
private final LocalSocketImpl localimpl;
boolean localClosed;
boolean localConnected;
// Constructors.
// -------------------------------------------------------------------------
public LocalSocket () throws SocketException
{
super ();
localimpl = new LocalSocketImpl ();
}
public LocalSocket (LocalSocketAddress addr) throws SocketException
{
this ();
try
{
connect (addr);
}
catch (IOException ioe)
{
SocketException se = new SocketException ();
se.initCause (ioe);
throw se;
}
}
LocalSocket (boolean nocreate) throws IOException
{
super ();
localimpl = new LocalSocketImpl (nocreate);
}
// Instance methods.
// -------------------------------------------------------------------------
public void bind (SocketAddress bindpoint) throws IOException
{
throw new SocketException ("binding local client sockets is nonsensical");
}
public void connect (SocketAddress endpoint, int timeout) throws IOException
{
if (isClosed ())
{
throw new SocketException ("socket is closed");
}
if (! (endpoint instanceof LocalSocketAddress))
{
throw new IllegalArgumentException ("socket address is not a local address");
}
if (getChannel() != null && !getChannel().isBlocking())
{
throw new IllegalBlockingModeException ();
}
try
{
localimpl.doCreate ();
localimpl.localConnect ((LocalSocketAddress) endpoint);
}
catch (IOException ioe)
{
close ();
throw ioe;
}
localConnected = true;
}
public InetAddress getInetAddress ()
{
return null;
}
public InetAddress getLocalAddress ()
{
return null;
}
public int getPort ()
{
return -1;
}
public int getLocalPort ()
{
return -1;
}
public SocketChannel getChannel ()
{
return null;
}
public SocketAddress getLocalSocketAddress ()
{
return localimpl.getLocalAddress ();
}
public SocketAddress getRemoteSocketAddress ()
{
return localimpl.getRemoteAddress ();
}
public InputStream getInputStream () throws IOException
{
return localimpl.getInputStream ();
}
public OutputStream getOutputStream () throws IOException
{
return localimpl.getOutputStream ();
}
public void sendUrgentData (int b) throws IOException
{
localimpl.sendUrgentData (b);
}
public synchronized void close () throws IOException
{
localimpl.close ();
localClosed = true;
}
public void shutdownInput () throws IOException
{
localimpl.shutdownInput ();
}
public void shutdownOutput () throws IOException
{
localimpl.shutdownOutput ();
}
public boolean isClosed ()
{
return localClosed;
}
public boolean isBound ()
{
return false;
}
public boolean isConnected ()
{
return localConnected;
}
// Unsupported methods.
// -------------------------------------------------------------------------
public void setTcpNoDelay (boolean b) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public boolean getTcpNoDelay() throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setSoLinger (boolean b, int i) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public int getSoLinger () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setOOBInline (boolean b) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public boolean getOOBInline () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setSoTimeout (int i) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public int getSoTimeout () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setSendBufferSize (int i) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public int getSendBufferSize() throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setReceiveBufferSize (int i) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public int getReceiveBufferSize () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setKeepAlive (boolean b) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public boolean getKeepAlive () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setTrafficClass (int i) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public int getTrafficClass () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public void setReuseAddress (boolean b) throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
public boolean getReuseAddress () throws SocketException
{
throw new SocketException ("local sockets do not support this option");
}
LocalSocketImpl getLocalImpl ()
{
return localimpl;
}
}

View file

@ -0,0 +1,100 @@
/* LocalSocketAddress.java -- unix-domain socket address.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a 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 of the License, 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; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, 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.net.local;
import java.net.SocketAddress;
public final class LocalSocketAddress extends SocketAddress
{
// Fields.
// -------------------------------------------------------------------------
private final String path;
// Constructor.
// -------------------------------------------------------------------------
/**
* Creates a new unix domain socket address.
*
* @param path The path to the socket.
* @throws NullPointerException If <i>path</i> is <tt>null</tt>.
*/
public LocalSocketAddress (String path)
{
if (path == null)
{
throw new NullPointerException ();
}
this.path = path;
}
// Instance methods.
// -------------------------------------------------------------------------
/**
* Returns the path of the socket.
*
* @return The path.
*/
public String getPath ()
{
return path;
}
public boolean equals (Object o)
{
if (!(o instanceof LocalSocketAddress))
{
return false;
}
return getPath ().equals (((LocalSocketAddress) o).getPath ());
}
public int hashCode ()
{
return path.hashCode();
}
public String toString ()
{
return super.toString() + " [ " + path + " ]";
}
}

View file

@ -0,0 +1,322 @@
/* LocalSocketImpl.java -- a unix domain client socket implementation.
Copyright (C) 2006 Free Software Foundation, Inc.
This file is a 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 of the License, 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; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, 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.net.local;
import java.io.FileDescriptor;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.SocketImpl;
final class LocalSocketImpl extends SocketImpl
{
// Fields.
// -------------------------------------------------------------------------
private boolean created;
private InputStream in;
private OutputStream out;
private int socket_fd;
private LocalSocketAddress local;
private LocalSocketAddress remote;
static
{
try
{
System.loadLibrary ("javanet");
}
catch (Exception x)
{
x.printStackTrace ();
}
}
// Constructor.
// -------------------------------------------------------------------------
LocalSocketImpl ()
{
this (false);
}
LocalSocketImpl (boolean nocreate)
{
created = nocreate;
socket_fd = -1;
fd = new FileDescriptor ();
}
// Instance methods.
// -------------------------------------------------------------------------
public void setOption (int opt, Object value) throws SocketException
{
throw new SocketException ("local sockets do not support options");
}
public Object getOption (int opt) throws SocketException
{
throw new SocketException ("local sockets do not support options");
}
protected native void create (boolean stream) throws IOException;
protected native void listen (int timeout) throws IOException;
protected native void accept (LocalSocketImpl socket) throws IOException;
protected native int available () throws IOException;
protected native void close () throws IOException;
protected native void sendUrgentData (int data) throws IOException;
protected native void shutdownInput () throws IOException;
protected native void shutdownOutput () throws IOException;
native void unlink () throws IOException;
native void localBind (LocalSocketAddress addr) throws IOException;
native void localConnect (LocalSocketAddress addr) throws IOException;
native int read (byte[] buf, int off, int len) throws IOException;
native void write (byte[] buf, int off, int len) throws IOException;
void doCreate () throws IOException
{
if (!created)
{
create (true);
}
}
LocalSocketAddress getLocalAddress ()
{
return local;
}
LocalSocketAddress getRemoteAddress ()
{
return remote;
}
protected InputStream getInputStream()
{
if (in == null)
{
in = new LocalInputStream (this);
}
return in;
}
protected OutputStream getOutputStream()
{
if (out == null)
{
out = new LocalOutputStream (this);
}
return out;
}
protected void accept (SocketImpl impl) throws IOException
{
if (! (impl instanceof LocalSocketImpl))
{
throw new IllegalArgumentException ("not a local socket");
}
accept ((LocalSocketImpl) impl);
}
protected void connect (String host, int port) throws IOException
{
throw new SocketException ("this is a local socket");
}
protected void connect (InetAddress addr, int port) throws IOException
{
throw new SocketException ("this is a local socket");
}
protected void connect(SocketAddress addr, int timeout) throws IOException
{
if (! (addr instanceof LocalSocketAddress))
{
throw new SocketException ("address is not local");
}
localConnect ((LocalSocketAddress) addr);
}
protected void bind (InetAddress addr, int port) throws IOException
{
throw new SocketException ("this is a local socket");
}
protected void bind (SocketAddress addr) throws IOException
{
if (! (addr instanceof LocalSocketAddress))
{
throw new SocketException ("address is not local");
}
localBind ((LocalSocketAddress) addr);
}
// Inner classes.
// -------------------------------------------------------------------------
class LocalInputStream extends InputStream
{
// Field.
// -----------------------------------------------------------------------
private final LocalSocketImpl impl;
// Constructor.
// -----------------------------------------------------------------------
LocalInputStream (LocalSocketImpl impl)
{
this.impl = impl;
}
// Instance methods.
// -----------------------------------------------------------------------
public int available () throws IOException
{
return impl.available();
}
public boolean markSupported ()
{
return false;
}
public void mark (int readLimit)
{
}
public void reset () throws IOException
{
throw new IOException ("mark/reset not supported");
}
public void close () throws IOException
{
impl.close();
}
public int read () throws IOException
{
byte[] buf = new byte[1];
int ret = read (buf);
if (ret != -1)
{
return buf[0] & 0xFF;
}
else
{
return -1;
}
}
public int read (byte[] buf) throws IOException
{
return read (buf, 0, buf.length);
}
public int read (byte[] buf, int off, int len) throws IOException
{
int ret = impl.read (buf, off, len);
if (ret == 0)
{
return -1;
}
return ret;
}
}
class LocalOutputStream extends OutputStream
{
// Field.
// -----------------------------------------------------------------------
private final LocalSocketImpl impl;
// Constructor.
// -----------------------------------------------------------------------
LocalOutputStream (LocalSocketImpl impl)
{
this.impl = impl;
}
// Instance methods.
// -----------------------------------------------------------------------
public void close () throws IOException
{
impl.close ();
}
public void flush () throws IOException
{
}
public void write (int b) throws IOException
{
byte[] buf = new byte [1];
buf[0] = (byte) b;
write (buf);
}
public void write (byte[] buf) throws IOException
{
write (buf, 0, buf.length);
}
public void write (byte[] buf, int off, int len) throws IOException
{
impl.write (buf, off, len);
}
}
}

View file

@ -160,7 +160,9 @@ public class Connection extends URLConnection
else if (c > 127) {
try {
byte [] c_as_bytes = Character.toString(c).getBytes("utf-8");
System.arraycopy(c_as_bytes, 0, buf, pos, c_as_bytes.length);
final int c_length = c_as_bytes.length;
System.arraycopy(c_as_bytes, 0, buf, pos, c_length);
pos += c_length;
}
catch (java.io.UnsupportedEncodingException x2) {
throw (Error) new InternalError().initCause(x2);

View file

@ -429,6 +429,9 @@ public class FTPConnection
public boolean changeWorkingDirectory(String path)
throws IOException
{
// Do nothing if the path is empty.
if (path.length() == 0)
return true;
String cmd = CWD + ' ' + path;
send(cmd);
FTPResponse response = getResponse();

View file

@ -48,12 +48,8 @@ import java.io.OutputStream;
import java.net.ProtocolException;
import java.net.URL;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.net.ssl.HandshakeCompletedEvent;
@ -271,6 +267,8 @@ public class HTTPURLConnection
secure = false;
start = 7;
int end = location.indexOf('/', start);
if (end == -1)
end = location.length();
host = location.substring(start, end);
int ci = host.lastIndexOf(':');
if (ci != -1)
@ -292,6 +290,8 @@ public class HTTPURLConnection
secure = true;
start = 8;
int end = location.indexOf('/', start);
if (end == -1)
end = location.length();
host = location.substring(start, end);
int ci = host.lastIndexOf(':');
if (ci != -1)
@ -410,10 +410,7 @@ public class HTTPURLConnection
}
public String getRequestProperty(String key)
{
if (key == null)
return null;
{
return requestHeaders.getValue(key);
}

View file

@ -50,7 +50,6 @@ import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
/**
* A collection of HTTP header names and associated values. The
@ -65,12 +64,18 @@ class Headers
{
/**
* A list of HeaderElements
*
*/
private final ArrayList headers = new ArrayList();
static final DateFormat dateFormat = new HTTPDateFormat();
/**
* The HTTP dateformat used to parse date header fields.
*/
private static final DateFormat dateFormat = new HTTPDateFormat();
/**
* Class for a Header element consisting of
* a name and value String.
*/
static class HeaderElement
{
String name;
@ -83,8 +88,12 @@ class Headers
}
}
/**
* Default constructor.
*/
public Headers()
{
// nothing to do
}
/**
@ -99,8 +108,11 @@ class Headers
}
/**
* Returns the value of the specified header as a string. If
* Returns the value of the specified header as a string. If
* multiple values are present, the last one is returned.
*
* @param header the header name (case insensitive search)
* @return The header value or <code>null</code> if not found.
*/
public String getValue(String header)
{
@ -116,8 +128,12 @@ class Headers
}
/**
* Returns the value of the specified header as an integer,
* or -1 if the header is not present or not an integer.
* Returns the value of the specified header as an integer. If
* multiple values are present, the last one is returned.
*
* @param header the header name (case insensitive search)
* @return The header value or <code>-1</code> if not present or
* not an integer value.
*/
public int getIntValue(String header)
{
@ -132,13 +148,18 @@ class Headers
}
catch (NumberFormatException e)
{
// fall through
}
return -1;
}
/**
* Returns the value of the specified header as a long, or -1 if the
* header is not present or cannot be parsed as a long.
* Returns the value of the specified header as a long. If
* multiple values are present, the last one is returned.
*
* @param header the header name (case insensitive search)
* @return The header value or <code>-1</code> if not present or
* not a long value.
*/
public long getLongValue(String header)
{
@ -153,13 +174,18 @@ class Headers
}
catch (NumberFormatException e)
{
// fall through
}
return -1;
}
/**
* Returns the value of the specified header as a date,
* or <code>null</code> if the header is not present or not a date.
* Returns the value of the specified header as a date. If
* multiple values are present, the last one is returned.
*
* @param header the header name (case insensitive search)
* @return The header value or <code>null</code> if not present or
* not a date value.
*/
public Date getDateValue(String header)
{
@ -180,23 +206,35 @@ class Headers
/**
* Add a header to this set of headers. If there is an existing
* header with the same name, it is discarded.
* header with the same name it's value is replaced with the new value.
* If multiple headers of the same name exist only the last one's value
* is replaced.
*
* @param name the header name
* @param value the header value
*
* @see #addValue
* @see #addValue(String, String)
*/
public void put(String name, String value)
{
remove(name);
headers.add(headers.size(), new HeaderElement(name, value));
{
for (int i = headers.size() - 1; i >= 0; i--)
{
HeaderElement e = (HeaderElement)headers.get(i);
if (e.name.equalsIgnoreCase(name))
{
e.value = value;
return;
}
}
// nothing was replaced so add it as new HeaderElement
addValue(name, value);
}
/**
* Add all headers from a set of headers to this set. If any of the
* headers to be added have the same name as existing headers, the
* existing headers will be discarded.
* Add all headers from a set of headers to this set. Any existing header
* with the same (case insensitive) name as one of the new headers will
* be overridden.
*
* @param o the headers to be added
*/
@ -206,10 +244,6 @@ class Headers
{
HeaderElement e = (HeaderElement)it.next();
remove(e.name);
}
for (Iterator it = o.iterator(); it.hasNext(); )
{
HeaderElement e = (HeaderElement)it.next();
addValue(e.name, e.value);
}
}
@ -234,6 +268,7 @@ class Headers
* Parse the specified InputStream, adding headers to this collection.
*
* @param in the InputStream.
* @throws IOException if I/O error occured.
*/
public void parse(InputStream in)
throws IOException
@ -303,7 +338,7 @@ class Headers
* @param name the header name
* @param value the header value
*
* @see #put
* @see #put(String, String)
*/
public void addValue(String name, String value)
{
@ -312,13 +347,14 @@ class Headers
/**
* Get a new Map containing all the headers. The keys of the Map
* are Strings (the header names). The values of the Map are
* are Strings (the header names). The headers will be included
* case-sensitive in the map so that querying must be done with the
* correct case of the needed header name. The values of the Map are
* unmodifiable Lists containing Strings (the header values).
*
* <p>
*
* The returned map is modifiable. Changing it will not effect this
* collection of Headers in any way.
* <p>
* The returned map is modifiable. Changing it will not effect this
* collection of Headers in any way.</p>
*
* @return a Map containing all the headers.
*/
@ -352,9 +388,9 @@ class Headers
*
* @param i the header index.
*
* @return the header name.
* @return The header name, or <code>null</code> if index outside of range.
*
* @see #getHeaderValue
* @see #getHeaderValue(int)
*/
public String getHeaderName(int i)
{
@ -369,9 +405,9 @@ class Headers
*
* @param i the header index.
*
* @return the header value.
* @return the header value, or <code>null</code> if index outside of range.
*
* @see #getHeaderName
* @see #getHeaderName(int)
*/
public String getHeaderValue(int i)
{

View file

@ -92,120 +92,126 @@ public class ChannelReader extends Reader
public int read(char[] buf, int offset, int count) throws IOException
{
// I declared channel being null meaning that the reader is closed.
if (!channel.isOpen())
throw new IOException("Reader was already closed.");
// I declared decoder being null meaning that there is no more data to read
// and convert.
if (decoder == null)
return -1;
// Stores the amount of character being read. It -1 so that if no conversion
// occured the caller will see this as an 'end of file'.
int sum = -1;
// Copies any characters which may be left from the last invocation into the
// destination array.
if (charBuffer.remaining() > 0)
synchronized (lock)
{
sum = Math.min(count, charBuffer.remaining());
charBuffer.get(buf, offset, sum);
// Updates the control variables according to the latest copy operation.
offset += sum;
count -= sum;
}
// Copies the character which have not been put in the destination array to
// the beginning. If data is actually copied count will be 0. If no data is
// copied count is >0 and we can now convert some more characters.
charBuffer.compact();
int converted = 0;
boolean last = false;
while (count != 0)
{
// Tries to convert some bytes (Which will intentionally fail in the
// first place because we have not read any bytes yet.)
CoderResult result = decoder.decode(byteBuffer, charBuffer, last);
if (result.isMalformed() || result.isUnmappable())
{
// JDK throws exception when bytes are malformed for sure.
// FIXME: Unsure what happens when a character is simply
// unmappable.
result.throwException();
}
// Marks that we should end this loop regardless whether the caller
// wants more chars or not, when this was the last conversion.
if (last)
{
decoder = null;
}
else if (result.isUnderflow())
{
// We need more bytes to do the conversion.
// Copies the not yet converted bytes to the beginning making it
// being able to receive more bytes.
byteBuffer.compact();
// Reads in another bunch of bytes for being converted.
if (channel.read(byteBuffer) == -1)
{
// If there is no more data available in the channel we mark
// that state for the final character conversion run which is
// done in the next loop iteration.
last = true;
}
// Prepares the byteBuffer for the next character conversion run.
byteBuffer.flip();
}
// Prepares the charBuffer for being drained.
charBuffer.flip();
converted = Math.min(count, charBuffer.remaining());
charBuffer.get(buf, offset, converted);
// Copies characters which have not yet being copied into the char-Array
// to the beginning making it possible to read them later (If data is
// really copied here, then the caller has received enough characters so
// far.).
charBuffer.compact();
// Updates the control variables according to the latest copy operation.
offset += converted;
count -= converted;
// Updates the amount of transferred characters.
sum += converted;
// I declared channel being null meaning that the reader is closed.
if (!channel.isOpen())
throw new IOException("Reader was already closed.");
// I declared decoder being null meaning that there is no more data to read
// and convert.
if (decoder == null)
return -1;
// Stores the amount of character being read. It -1 so that if no conversion
// occured the caller will see this as an 'end of file'.
int sum = -1;
// Copies any characters which may be left from the last invocation into the
// destination array.
if (charBuffer.remaining() > 0)
{
break;
sum = Math.min(count, charBuffer.remaining());
charBuffer.get(buf, offset, sum);
// Updates the control variables according to the latest copy operation.
offset += sum;
count -= sum;
}
// Now that more characters have been transfered we let the loop decide
// what to do next.
// Copies the character which have not been put in the destination array to
// the beginning. If data is actually copied count will be 0. If no data is
// copied count is >0 and we can now convert some more characters.
charBuffer.compact();
int converted = 0;
boolean last = false;
while (count != 0)
{
// Tries to convert some bytes (Which will intentionally fail in the
// first place because we have not read any bytes yet.)
CoderResult result = decoder.decode(byteBuffer, charBuffer, last);
if (result.isMalformed() || result.isUnmappable())
{
// JDK throws exception when bytes are malformed for sure.
// FIXME: Unsure what happens when a character is simply
// unmappable.
result.throwException();
}
// Marks that we should end this loop regardless whether the caller
// wants more chars or not, when this was the last conversion.
if (last)
{
decoder = null;
}
else if (result.isUnderflow())
{
// We need more bytes to do the conversion.
// Copies the not yet converted bytes to the beginning making it
// being able to receive more bytes.
byteBuffer.compact();
// Reads in another bunch of bytes for being converted.
if (channel.read(byteBuffer) == -1)
{
// If there is no more data available in the channel we mark
// that state for the final character conversion run which is
// done in the next loop iteration.
last = true;
}
// Prepares the byteBuffer for the next character conversion run.
byteBuffer.flip();
}
// Prepares the charBuffer for being drained.
charBuffer.flip();
converted = Math.min(count, charBuffer.remaining());
charBuffer.get(buf, offset, converted);
// Copies characters which have not yet being copied into the char-Array
// to the beginning making it possible to read them later (If data is
// really copied here, then the caller has received enough characters so
// far.).
charBuffer.compact();
// Updates the control variables according to the latest copy operation.
offset += converted;
count -= converted;
// Updates the amount of transferred characters.
sum += converted;
if (decoder == null)
{
break;
}
// Now that more characters have been transfered we let the loop decide
// what to do next.
}
// Makes the charBuffer ready for reading on the next invocation.
charBuffer.flip();
return sum;
}
// Makes the charBuffer ready for reading on the next invocation.
charBuffer.flip();
return sum;
}
public void close() throws IOException
{
channel.close();
synchronized (lock)
{
channel.close();
// Makes sure all intermediate data is released by the decoder.
if (decoder != null)
decoder.reset();
// Makes sure all intermediate data is released by the decoder.
if (decoder != null)
decoder.reset();
}
}
}

View file

@ -0,0 +1,190 @@
/* ChannelWriter.java -- nio / writer bridge
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.nio;
import java.io.IOException;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
/**
* A Writer implementation that works by wrapping an NIO channel.
*/
public class ChannelWriter
extends Writer
{
private static final int DEFAULT_BUFFER_CAP = 8192;
/**
* The output channel.
*/
private WritableByteChannel byteChannel;
/**
* The encoder to use.
*/
private CharsetEncoder enc;
/**
* The byte buffer. Translated characters are stored here on their way out.
*/
private ByteBuffer byteBuffer;
/**
* The character buffer. Characters are stored here on their way into
* the encoder.
*/
private CharBuffer charBuffer;
private void writeBuffer() throws IOException
{
byteBuffer.flip();
byteChannel.write(byteBuffer);
}
/**
* Create a new instance, given the output byte channel, the encoder
* to use, and the minimum buffer capacity.
*/
public ChannelWriter(WritableByteChannel ch, CharsetEncoder enc,
int minBufferCap)
{
this.byteChannel = ch;
this.enc = enc;
if (minBufferCap == -1)
minBufferCap = DEFAULT_BUFFER_CAP;
this.byteBuffer
= ByteBuffer.allocate((int) (minBufferCap * enc.maxBytesPerChar()));
this.charBuffer = CharBuffer.allocate(minBufferCap);
this.charBuffer.clear();
}
/* (non-Javadoc)
* @see java.io.Writer#flush()
*/
public void flush() throws IOException
{
// Presumably if we have characters in our buffer, it is
// due to an underflow. So we don't bother trying to flush
// that here.
}
/* (non-Javadoc)
* @see java.io.Writer#close()
*/
public void close() throws IOException
{
synchronized (lock)
{
if (enc == null)
throw new IOException("writer already closed");
byteBuffer.clear();
charBuffer.flip();
CoderResult res = enc.encode(charBuffer, byteBuffer, true);
if (res.isError() || res.isMalformed() || res.isUnmappable())
res.throwException();
writeBuffer();
byteBuffer.clear();
res = enc.flush(byteBuffer);
if (res.isError() || res.isMalformed() || res.isUnmappable())
res.throwException();
writeBuffer();
enc = null;
}
}
/* (non-Javadoc)
* @see java.io.Writer#write(char[], int, int)
*/
public void write(char[] buf, int offset, int len) throws IOException
{
synchronized (lock)
{
if (enc == null)
throw new IOException("writer already closed");
int lastLen = -1;
while (len > 0)
{
// Copy data into our character buffer.
int allowed = Math.min(charBuffer.remaining(), len);
charBuffer.put(buf, offset, allowed);
// Update for the next pass through the loop.
offset += allowed;
len -= allowed;
charBuffer.flip();
// If we didn't make any progress, we want to clean up
// and save our state for the next write().
if (len == lastLen)
{
if (len <= charBuffer.remaining())
{
charBuffer.put(buf, offset, len);
charBuffer.flip();
}
else
{
CharBuffer ncb = CharBuffer.allocate(charBuffer.length()
+ len);
ncb.put(charBuffer);
ncb.put(buf, offset, len);
charBuffer = ncb;
}
break;
}
lastLen = len;
// Convert.
byteBuffer.clear();
CoderResult res = enc.encode(charBuffer, byteBuffer, false);
// Compact here, as we want to leave the buffer in the
// right state for any future put()s.
charBuffer.compact();
if (res.isError() || res.isMalformed() || res.isUnmappable())
res.throwException();
// Write the byte buffer to the output channel.
writeBuffer();
}
}
}
}

View file

@ -0,0 +1,406 @@
/* ActivationSystemTransient.java -- The transient RMI object activation system.
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.rmi.activation;
import java.rmi.MarshalledObject;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationGroupDesc;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
import java.rmi.activation.ActivationMonitor;
import java.rmi.activation.ActivationSystem;
import java.rmi.activation.Activator;
import java.rmi.activation.UnknownGroupException;
import java.rmi.activation.UnknownObjectException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
/**
* Provides the default transient activation system.
*
* @author Audrius Meskauskas (audriusa@bioinformatics.org)
*/
public class ActivationSystemTransient
extends DefaultActivationSystem
implements ActivationSystem, ActivationMonitor, Activator
{
/**
* Maps group identifiers into group descriptions.
*/
protected final BidiTable groupDescs;
/**
* Maps object identifiers into object activation descriptions
*/
protected final BidiTable descriptions;
/**
* Maps group identifiers into already activated groups.
*/
protected transient final Map groupInstantiators = new Hashtable();
/**
* The cache of the activated objects, maps activation ids to remote
* object stubs.
*/
protected transient final Map activatedObjects = new HashMap();
/**
* The object incarnation counter.
*/
static long groupIncarnations = 0;
/**
* The singleton of this activation system
*/
static ActivationSystem singleton;
/**
* Set to true to print the event messages to console.
*/
public static boolean debug = false;
/**
* Creates the group which uses the given maps to store the data.
*/
protected ActivationSystemTransient(BidiTable objectDescriptions,
BidiTable groupDescriptiopns)
{
descriptions = objectDescriptions;
groupDescs = groupDescriptiopns;
}
/**
* Creates the group with transient maps.
*/
protected ActivationSystemTransient()
{
this (new BidiTable(), new BidiTable());
}
public static ActivationSystem getInstance()
{
if (singleton == null)
singleton = new ActivationSystemTransient();
return singleton;
}
/**
* Activate the given object (try cache first if force = false)
*/
public MarshalledObject activate(ActivationID id, boolean force)
throws ActivationException, UnknownObjectException, RemoteException
{
if (! force)
{
synchronized (activatedObjects)
{
MarshalledObject object = (MarshalledObject) activatedObjects.get(id);
if (object != null)
return object;
}
}
ActivationDesc desc = (ActivationDesc) descriptions.get(id);
if (desc == null)
throw new UnknownObjectException("Activating unknown object "+
id == null ? "null" : id.toString());
ActivationInstantiator group =
(ActivationInstantiator) groupInstantiators.get(desc.getGroupID());
if (group == null)
{
// The group is not active - must be activated.
ActivationGroupID gid = desc.getGroupID();
ActivationGroupDesc adesc = (ActivationGroupDesc) groupDescs.get(gid);
if (adesc == null)
throw new UnknownGroupException("Activating unknown group "
+ gid + " for "+ id+" this "+this);
synchronized (ActivationSystemTransient.class)
{
groupIncarnations++;
}
group = ActivationGroup.createGroup(gid, adesc, groupIncarnations);
activeGroup(gid, group, groupIncarnations);
}
MarshalledObject object = group.newInstance(id, desc);
synchronized (activatedObjects)
{
activatedObjects.put(id, object);
}
return object;
}
/**
* Returns the activation monitor (THIS) and remebers the instantiator, used
* by that group.
*/
public ActivationMonitor activeGroup(ActivationGroupID id,
ActivationInstantiator group,
long incarnation)
throws UnknownGroupException, ActivationException, RemoteException
{
groupInstantiators.put(id, group);
return this;
}
/**
* Get the activation descriptor for the given activation id.
*
* @return the activation descriptor, never null.
* @throws UnknownObjectException if such object is unknown.
*/
public ActivationDesc getActivationDesc(ActivationID id)
throws ActivationException, UnknownObjectException, RemoteException
{
ActivationDesc desc = (ActivationDesc) descriptions.get(id);
if (desc == null)
throw new UnknownObjectException("No desc for "+
id == null ? "null" : id.toString());
return desc;
}
/**
* Get the descriptor of the given activation group.
*
* @return the activation group descriptor, never null.
* @throws UnknownGroupException if such group is unknown
*/
public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID groupId)
throws ActivationException, UnknownGroupException, RemoteException
{
ActivationGroupDesc desc = (ActivationGroupDesc) groupDescs.get(groupId);
if (desc == null)
throw new UnknownGroupException(groupId == null ? "null"
: groupId.toString());
return desc;
}
/**
* Create the activation group id and put this id-descriptor combination into
* the group map. The new ID will only be created if this description has not
* already been registered, otherwise the id of the registered description
* will be returned.
*/
public ActivationGroupID registerGroup(ActivationGroupDesc groupDesc)
throws ActivationException, RemoteException
{
ActivationGroupID id = (ActivationGroupID) groupDescs.getKey(groupDesc);
if (id == null)
{
id = new ActivationGroupID(this);
groupDescs.put(id, groupDesc);
}
if (debug)
System.out.println("Register group " + id +":"+groupDesc+" this "+this);
return id;
}
/**
* Create the object activation id and put this id-descriptor combination into
* the group map. The new ID will only be created if this description has not
* already been registered, otherwise the id of the registered description
* will be returned.
*/
public ActivationID registerObject(ActivationDesc desc)
throws ActivationException, UnknownGroupException, RemoteException
{
ActivationID id = (ActivationID) descriptions.getKey(desc);
if (id == null)
{
id = new ActivationID(this);
descriptions.put(id, desc);
}
if (debug)
System.out.println("Register object " + id +":"+desc+" this "+this);
return id;
}
/**
* Replace the activation descriptor, return the previous descriptor.
*/
public ActivationDesc setActivationDesc(ActivationID id, ActivationDesc desc)
throws ActivationException, UnknownObjectException,
UnknownGroupException, RemoteException
{
ActivationDesc prev = getActivationDesc(id);
descriptions.put(id, desc);
return prev;
}
/**
* Replace the activation group descriptor, return the previous descriptor.
*/
public ActivationGroupDesc setActivationGroupDesc(
ActivationGroupID groupId,
ActivationGroupDesc groupDesc)
throws ActivationException, UnknownGroupException, RemoteException
{
ActivationGroupDesc prev = getActivationGroupDesc(groupId);
groupDescs.put(groupId, groupDesc);
return prev;
}
/**
* Calls .shutdown on all bidirectional tables (has no effect if these
* table are not persistent).
*/
public void shutdown() throws RemoteException
{
descriptions.shutdown();
groupDescs.shutdown();
}
/**
* Remove the group from the group map
*/
public void unregisterGroup(ActivationGroupID groupId) throws ActivationException,
UnknownGroupException, RemoteException
{
if (! groupDescs.containsKey(groupId))
throw new UnknownGroupException("Unknown group "+groupId);
groupDescs.removeKey(groupId);
groupInstantiators.remove(groupId);
}
/**
* Remove the object id from the active object and description maps.
*/
public void unregisterObject(ActivationID id) throws ActivationException,
UnknownObjectException, RemoteException
{
if (! descriptions.containsKey(id))
throw new UnknownObjectException("Unregistering unknown object");
descriptions.removeKey(id);
synchronized (activatedObjects)
{
activatedObjects.remove(id);
}
}
/**
* Put the object into active object map.
*/
public void activeObject(ActivationID id, MarshalledObject obj)
throws UnknownObjectException, RemoteException
{
if (! descriptions.containsKey(id))
throw new UnknownObjectException("Activating unknown object "+
id+" this "+this);
try
{
synchronized (activatedObjects)
{
activatedObjects.put(id, obj.get());
}
}
catch (RemoteException e)
{
throw e;
}
catch (Exception e)
{
UnknownObjectException un = new UnknownObjectException(
"Cannot get Remote for MarshalledObject of "+id);
un.detail = e;
throw un;
}
}
/**
* Check if the group is known. Remove all active objects, belonging to
* that group, from the active object cache.
*/
public void inactiveGroup(ActivationGroupID groupId, long incarnation)
throws UnknownGroupException, RemoteException
{
if (! groupInstantiators.containsKey(groupId))
throw new UnknownGroupException("Inactivating unkwnon group");
groupInstantiators.remove(groupId);
// Remove all members of this group from the cache.
synchronized (activatedObjects)
{
Iterator iter = activatedObjects.keySet().iterator();
ActivationID id;
ActivationDesc desc;
while (iter.hasNext())
{
id = (ActivationID) iter.next();
desc = (ActivationDesc) descriptions.get(id);
if (desc.getGroupID().equals(groupId))
activatedObjects.remove(id);
}
}
}
/**
* Removes this id from the active object cache.
*/
public void inactiveObject(ActivationID id) throws UnknownObjectException,
RemoteException
{
if (! descriptions.containsKey(id))
throw new UnknownObjectException("Inactivating unknown object");
synchronized (activatedObjects)
{
activatedObjects.remove(id);
}
}
}

View file

@ -0,0 +1,163 @@
/* BidiHasthable.java -- Bidirectional hash table.
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.rmi.activation;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* The bidirectional hash table, maps both a to b and b to a.
*
* @author Audrius Meskauskas (audriusa@bioinformatics.org)
*/
public class BidiTable
{
/**
* Use serialVerionUID for interoperability.
*/
private static final long serialVersionUID = 1;
/**
* Maps keys to values
*/
protected Map k2v;
/**
* Maps values to keys (in reverse)
*/
protected Map v2k;
/**
* Create a new table that is ready to use.
*/
public BidiTable()
{
k2v = new HashMap();
v2k = new HashMap();
}
/**
* Create a new instance where the hashtable fields are not initialised
* (called from derivatives that intialise hashtables in they own way.
*
* @param flags currently used to mark the different constructor only.
*/
protected BidiTable(int flags)
{
}
/**
* Get key by value
*/
public synchronized Object getKey(Object value)
{
return v2k.get(value);
}
/**
* Put key-value pair.
*/
public synchronized void put(Object key, Object value)
{
k2v.put(key, value);
v2k.put(value, key);
}
/**
* Get value from key
*/
public synchronized Object get(Object key)
{
return k2v.get(key);
}
/**
* Remove the key-value pair by key
*/
public synchronized void removeKey(Object key)
{
Object value = k2v.get(key);
if (value!=null)
{
k2v.remove(key);
v2k.remove(value);
}
}
/**
* Check if the table contains this key.
*/
public synchronized boolean containsKey(Object key)
{
return k2v.containsKey(key);
}
/**
* This method is called before exit and may be used to write the database
* to the disk. The default method does nothing.
*/
public synchronized void shutdown()
{
}
/**
* Get the size.
*/
public synchronized int size()
{
return k2v.size();
}
/**
* Get the key collection.
*/
public synchronized Object[] keys()
{
Collection keys = k2v.keySet();
Object[] k = new Object[keys.size()];
Iterator iter = keys.iterator();
for (int i = 0; i < k.length; i++)
k[i] = iter.next();
return k;
}
}

View file

@ -0,0 +1,159 @@
/* DefaultActivationGroup.java -- Default activation group.
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.rmi.activation;
import gnu.java.rmi.server.ActivatableServerRef;
import gnu.java.rmi.server.UnicastServer;
import java.lang.reflect.Constructor;
import java.rmi.MarshalledObject;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationGroup;
import java.rmi.activation.ActivationGroupID;
import java.rmi.activation.ActivationID;
import java.rmi.activation.UnknownObjectException;
/**
* The default activation group class. This activation group assumes that
* all classes are accessible via current thread context class loader.
* The remote class loading is not supported for security reasons. The
* activation always occurs in the current jre.
*
* @author Audrius Meskauskas (audriusa@Bioinformatics.org)
*/
public class DefaultActivationGroup
extends ActivationGroup
{
/**
* Use the serialVersionUID for interoperability.
*/
private static final long serialVersionUID = 1;
/**
* Used during the group creation (required constructor).
*/
static final Class[] cConstructorTypes = new Class[]
{
ActivationID.class,
MarshalledObject.class
};
/**
* Create the new default activation group.
*
* @param id the group activation id.
* @param data may contain the group initialization data (unused and can be
* null)
* @throws RemoteException if the super constructor does
*/
public DefaultActivationGroup(ActivationGroupID id, MarshalledObject data)
throws RemoteException
{
super(id);
}
/**
* May be overridden and used as a hook. This method is called each time
* the new object is instantiated.
*/
public void activeObject(ActivationID id, Remote obj)
throws ActivationException, UnknownObjectException, RemoteException
{
// Nothing to do (the monitor is already notified in newInstance)
}
/**
* Create the new instance of the object, using the class name and location
* information, stored in the passed descriptor. The method expects the object
* class to have the two parameter constructor, the first parameter being the
* {@link ActivationID} and the second the {@link MarshalledObject}.
*
* @param id the object activation id
* @param desc the activation descriptor, providing the information, necessary
* to create and activate the object
* @return the marshalled object, containing the exported stub of the created
* object
* @throws ActivationException if the activation fails due any reason
*/
public MarshalledObject newInstance(ActivationID id, ActivationDesc desc)
throws ActivationException, RemoteException
{
try
{
if (ActivationSystemTransient.debug)
System.out.println("Instantiating "+desc.getClassName());
Remote object;
Class objectClass;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
objectClass = loader.loadClass(desc.getClassName());
Constructor constructor = objectClass.getConstructor(cConstructorTypes);
object = (Remote) constructor.newInstance(
new Object[] { id, desc.getData() });
// Make the object accessible and create the stub.
ActivatableServerRef ref = UnicastServer.getActivatableRef(id);
Remote stub = ref.exportObject(object);
MarshalledObject marsh = new MarshalledObject(stub);
// Notify the activation monitor.
activeObject(id, marsh);
// Make call to the hook that may be overridden.
activeObject(id, stub);
return marsh;
}
catch (Exception e)
{
ActivationException acex = new ActivationException(
"Unable to activate "+ desc.getClassName()
+ " from "+ desc.getLocation(), e);
throw acex;
}
}
}

View file

@ -0,0 +1,118 @@
/* DefaultActivationSystem.java -- Default RMI activation system
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.rmi.activation;
import java.rmi.activation.ActivationSystem;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* Finds and returns the default activation system for this jre.
*
* @author Audrius Meskauskas (audriusa@bioinformatics.org)
*/
public abstract class DefaultActivationSystem
{
/**
* The activation system (assigned if once found).
*/
static ActivationSystem system;
/**
* The default activation registry port.
*/
static int ACTIVATION_REGISTRY_PORT;
/**
* The name of the activation system registry port property.
*/
static String AS_PORT_PROPERTY = "java.rmi.activation.port";
/**
* The defalut name of the activation system in the activation registry.
*/
static String ACTIVATION_SYSTEM_NAME = "java.rmi.activation.ActivationSystem";
/**
* Get the activation system, default for this jre. If no external activation
* system exists, the internal activation system will be activated. This
* internal system is limited in capabilities and should be used exclusively
* for automated testing, to avoid necessity of starting rmi daemon during
* testing process.
*/
public static ActivationSystem get()
{
if (system == null)
try
{
// Obtain the port:
String asr = System.getProperty("java.rmi.activation.port");
if (asr != null)
{
try
{
ACTIVATION_REGISTRY_PORT = Integer.parseInt(asr);
if (ACTIVATION_REGISTRY_PORT <= 0)
throw new InternalError("Invalid " + asr + " value, "
+ ACTIVATION_REGISTRY_PORT);
}
catch (NumberFormatException e)
{
throw new InternalError("Unable to parse " + asr
+ " to integer");
}
}
else
ACTIVATION_REGISTRY_PORT = ActivationSystem.SYSTEM_PORT;
// Expect the naming service running first.
// The local host may want to use the shared registry
Registry r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT);
ActivationSystem system = (ActivationSystem) r.lookup(ACTIVATION_SYSTEM_NAME);
return system;
}
catch (Exception ex)
{
system = ActivationSystemTransient.getInstance();
}
return system;
}
}

View file

@ -38,6 +38,7 @@ exception statement from your version. */
package gnu.java.rmi.dgc;
import gnu.java.rmi.server.UnicastServer;
import gnu.java.rmi.server.UnicastServerRef;
import java.rmi.RemoteException;
@ -46,7 +47,8 @@ import java.rmi.dgc.Lease;
import java.rmi.dgc.VMID;
import java.rmi.server.ObjID;
import java.rmi.server.RMISocketFactory;
import java.util.Hashtable;
import java.util.Collection;
import java.util.TimerTask;
/**
* The DGC implementation is used for the server side during the distributed
@ -67,15 +69,68 @@ public class DGCImpl
* UnicastRemoteObject must exportObject automatically.
*/
/**
* Use the serial version UID for interoperability.
*/
private static final long serialVersionUID = 1;
/**
* Protects the array of object Id's for the scheduled period of time
* (lease). After the time expires, the protector is automatically discarded,
* making the references unprotected and hence applicable for the garbage
* collection.
*/
class RefProtector extends TimerTask
{
/**
* The corresponding server references to protect. Each Id may contain
* multiple references that are stored to collection.
*/
Collection[] references;
/**
* Create the new instance of the reference protector that protects the
* given array of ids and exists for the given period of time.
*
* @param ids the ids to protect.
*/
RefProtector(ObjID[] ids, long timeToLive)
{
references = new Collection[ids.length];
for (int i = 0; i < ids.length; i++)
{
references[i] = UnicastServer.getExported(ids[i]);
}
// Schedule the existence.
LeaseRenewingTask.timer.schedule(this, timeToLive);
}
/**
* Break all links, ensuring easy collection of the references by the gc.
*/
public void run()
{
for (int i = 0; i < references.length; i++)
{
references[i].clear();
references[i] = null;
}
}
}
/**
* This defauld lease value is used if the lease value, passed to the
* {@link #dirty} is equal to zero.
*/
static final long LEASE_VALUE = 600000L;
// leaseCache caches a LeaseRecord associated with a vmid
Hashtable leaseCache = new Hashtable();
/**
* Create the new DGC implementation.
*
* @throws RemoteException if the super constructor throws or the
* socket factory fails.
*/
public DGCImpl() throws RemoteException
{
super(new ObjID(ObjID.DGC_ID), 0, RMISocketFactory.getSocketFactory());
@ -92,26 +147,20 @@ public class DGCImpl
*/
public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease)
throws RemoteException
{
VMID vmid = lease.getVMID();
if (vmid == null)
vmid = new VMID();
{
// We do not fill in VMID because in this implementation it is not used.
long leaseValue = lease.getValue();
// Grant the maximal default lease time if the passed value is zero.
if (leaseValue <= 0)
leaseValue = LEASE_VALUE;
lease = new Lease(vmid, leaseValue);
LeaseRecord lr = (LeaseRecord) leaseCache.get(vmid);
if (lr != null)
lr.reset(leaseValue);
else
{
lr = new LeaseRecord(vmid, leaseValue, ids);
leaseCache.put(vmid, lr);
}
return (lease);
// Create (and shedule of the given existence) the new reference
// protector.
new RefProtector(ids, leaseValue);
lease = new Lease(lease.getVMID(), leaseValue);
return lease;
}
/**
@ -130,65 +179,4 @@ public class DGCImpl
// TODO implement
}
/**
* LeaseRecord associates a vmid to expireTime.
*/
static class LeaseRecord
{
/**
* The lease id.
*/
final VMID vmid;
/**
* The lease expiration time.
*/
long expireTime;
/**
* The array of ObjeID's that must be protected from being garbage
* collected.
*/
final ObjID [] objects;
/**
* Create the new lease record.
*
* @param vmid lease id.
* @param leaseValue lease value
*/
LeaseRecord(VMID vmid, long leaseValue, ObjID [] an_objects)
{
this.vmid = vmid;
reset(leaseValue);
objects = an_objects;
}
/**
* Prolong the expiration time till current time + passed value
*
* @param leaseValue the value after that (since the current moment)
* the lease should expire in the future.
*/
void reset(long leaseValue)
{
long l = System.currentTimeMillis();
expireTime = l + leaseValue;
}
/**
* Check if the lease has been expired.
*
* @return true if the lease has been expired, false if it is still valid.
*/
boolean isExpired()
{
long l = System.currentTimeMillis();
if (l > expireTime)
return true;
return false;
}
} // End of LeaseRecord
} // End of DGCImpl

View file

@ -0,0 +1,234 @@
/* LeaseRenewingTask.java -- The task to renew the lease.
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.rmi.dgc;
import gnu.java.rmi.server.UnicastRef;
import java.lang.ref.WeakReference;
import java.rmi.dgc.Lease;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;
/**
* The task to renew the lease to some object reference. The UnicastRef
* being renewed is stored as a weak reference. So the presence of the
* sheduled task does not prevent it from being garbage collected. If the
* reference has not been garbage collected, the task is resheduled after
* the lease is renewed.
*
* @author Audrius Meskauskas (Audriusa@Bioinformatics.org)
*/
public class LeaseRenewingTask
{
/**
* The sheduled timer task to call the renew() method.
*/
class LeaseTimerTask extends TimerTask
{
public void run()
{
renew();
}
}
/**
* The default requested lease duration time (one minute by default).
*/
public static long REQUEST_LEASE_DURATION = 60000;
/**
* The reference to the UnicastRef that must renew its lease until not
* garbage collected. The different members of this list may point to the
* different instances of the UnicastRef's, but these references are
* pointing to the same remote object (they .equals() returns
* true when comparing with each other). Using LinkedList to make
* frequent deletions from the middle easy.
*/
LinkedList ref = new LinkedList();
/**
* The granted (or supposed) lease.
*/
Lease lease = new Lease(null, REQUEST_LEASE_DURATION);
/**
* The timer, shared by all lease renewing tasks. The same instance is also
* used for the reference protector discarding in DGCImpl.
*/
static Timer timer = new Timer(true);
/**
* Maps the UnicastRef to its renewing task.
*/
static WeakHashMap existingTasks = new WeakHashMap();
/**
* Creates the lease renewing task that renews the lease of the given
* UnicastRef until it is not collected. This constructor requests the lease
* value from the server and schedules the lease renewal action.
*
* @param renewIt the reference that must be renewed.
*/
public LeaseRenewingTask(UnicastRef renewIt)
{
lease = notifyDGC(renewIt);
if (lease != null)
{
schedule(lease);
ref.add(new WeakReference(renewIt));
}
}
/**
* Schedule periodic leases for the given UnicastRef reference.
*
* @param renewIt the reference, for that the leases must be scheduled.
*/
public static void scheduleLeases(UnicastRef renewIt)
{
// No need to schedule leases for null.
if (renewIt == null)
return;
try {
synchronized (existingTasks)
{
// Check maybe the task for refreshing this remote object already
// exists.
LeaseRenewingTask task = (LeaseRenewingTask) existingTasks.get(renewIt);
if (task != null)
{
// Extend the reference list only. The scheduling must be
// alredy done with the previous lease.
synchronized (task.ref)
{
task.ref.add(new WeakReference(renewIt));
}
}
else
existingTasks.put(renewIt, new LeaseRenewingTask(renewIt));
}
}
catch (Exception ex)
{
InternalError ierr = new InternalError("Lease for "+renewIt);
ierr.initCause(ex);
throw ierr;
}
}
/**
* Shedule the renewing call, taking into consideration that the following
* lease was granted.
*
* @param lease the lease that was granted.
*/
public void schedule(Lease lease)
{
long value = lease.getValue();
// Shedule a 10 % earlier because some time is needed for the message
// to reach the server.
long reduced = (value * 90)/100;
if (reduced == 0)
reduced = value;
timer.schedule(new LeaseTimerTask(), reduced);
}
/**
* Renew the lease.
*/
public void renew()
{
Object renewIt = null;
// Iterate throw the list of associated references. If all are
// discarded, there is no need to renew.
synchronized (ref)
{
Iterator iter = ref.iterator();
WeakReference w;
while (iter.hasNext() && renewIt == null)
{
w = (WeakReference) iter.next();
renewIt = w.get();
if (renewIt == null)
// Discard the weak reference if its target has been garbage
// collected.
iter.remove();
}
}
if (renewIt!=null)
{
Lease lease = notifyDGC( (UnicastRef) renewIt);
// Schedule the next renewing session.
if (lease!=null)
schedule(lease);
}
{
// All references collected - discard this entry.
}
}
/**
* Notify DGC that we still hold this reference.
*
* @param renewIt the reference we still have (must not be null).
*/
public Lease notifyDGC(UnicastRef renewIt)
{
try
{
return renewIt.notifyDGC(lease);
}
catch (Exception e)
{
// Failed to notify.
// TODO Take some relevant action in the case if we failed
// to notify the remote object owner.
return null;
}
}
}

View file

@ -0,0 +1,175 @@
/* ActivatableRef.java -- Activatable server reference
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.rmi.server;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationID;
import java.rmi.server.ObjID;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.rmi.server.RemoteRef;
/**
* The activatable reference works like UnicastRef, but if the remote object
* appears to be not accessible, it tries to reactivate it before reporting
* any errors. Apart the fields of the UnicastRef, the activatable reference
* contains the ActivationID that is used for this activation.
*
* @author Audrius Meskauskas (Audriusa@Bioinformatics.org)
*/
public class ActivatableRef extends UnicastRef
{
/**
* Use serial version UID for iteroperability
*/
private static final long serialVersionUID = 1;
/**
* The activation id.
*/
ActivationID actId;
/**
* Delegate call to the superclass.
*/
public ActivatableRef()
{
super();
}
/**
* Delegate call to the superclass.
*/
public ActivatableRef(ObjID objid, String host, int port,
RMIClientSocketFactory csf)
{
super(objid, host, port, csf);
}
/**
* Delegate call to the superclass.
*/
public ActivatableRef(ObjID objid)
{
super(objid);
}
/**
* Get the referencing class.
*/
public String getRefClass(ObjectOutput out)
{
return "ActivatableRef";
}
/**
* Read the content from the input stream.
*/
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException
{
super.readExternal(in);
actId = (ActivationID) in.readObject();
}
/**
* Write the content to the output stream.
*/
public void writeExternal(ObjectOutput out) throws IOException
{
super.writeExternal(out);
out.writeObject(actId);
}
/**
* Invoke the remote method on the given object and try to activate the object
* if it is not reacheable with the current manager.
*/
protected Object invokeCommon(Remote obj, Method method, Object[] params,
int opnum, long hash) throws Exception
{
UnicastConnection conn;
try
{
conn = manager.getConnection();
}
catch (IOException e1)
{
// Connection failed: try to activate.
Remote reactivated = actId.activate(false);
if (reactivated instanceof RemoteObject)
{
RemoteRef ref = ((RemoteObject) reactivated).getRef();
manager = ((UnicastRef) ref).manager;
}
else if (Proxy.isProxyClass(reactivated.getClass()))
{
RemoteObjectInvocationHandler hander =
(RemoteObjectInvocationHandler)
Proxy.getInvocationHandler(reactivated);
RemoteRef ref = hander.getRef();
manager = ((UnicastRef) ref).manager;
}
else
throw new ActivationException("Activating into unsupported class "
+ reactivated.getClass());
try
{
conn = manager.getConnection();
}
catch (IOException e2)
{
throw new RemoteException("connection failed to host: "
+ manager.serverName, e1);
}
}
return invokeCommon(conn, obj, method, params, opnum, hash);
}
}

View file

@ -0,0 +1,227 @@
/* ActivatableServerRef.java -- The activatable server reference
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.rmi.server;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.activation.ActivationID;
import java.rmi.server.ObjID;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.RemoteStub;
import java.rmi.server.Skeleton;
/**
* The activatable server reference works like UnicastServerReference, but it
* additionally activates the associated object on demand, during the first
* incoming call. When UnicastServerReference takes the working reference,
* the ActivatableServerRef takes the activation id instead.
*
* @author Audrius Meskauskas (Audriusa@Bioinformatics.org)
*/
public class ActivatableServerRef extends UnicastServerRef
{
/**
* Use SVUID for interoperability
*/
private static final long serialVersionUID = 1;
/**
* The object activation id.
*/
public ActivationID actId;
/**
* Used by serialization only
*/
public ActivatableServerRef()
{
super();
}
/**
* Create the new activatable server reference that will activate object on
* the first call using the given activation id.
*/
public ActivatableServerRef(ObjID id, ActivationID anId, int aPort,
RMIServerSocketFactory ssFactory)
throws RemoteException
{
super(id, aPort, ssFactory);
actId = anId;
// The object ID will be placed in the object map and should deliver
// incoming call to {@link #incommingMessageCall}. The object itself
// is currently null.
UnicastServer.exportActivatableObject(this);
}
/**
* Inactivate the object (stop the server).
*/
public void inactivate()
{
manager.stopServer();
}
/**
* Activate the object (normally during the first call).
*/
protected void activate() throws RemoteException
{
try
{
Remote self = actId.activate(false);
// This will call UnicastServer.exportObject, replacing null by
// the activated object (self) in the object map.
exportObject(self);
}
catch (RemoteException rex)
{
throw rex;
}
catch (Exception exc)
{
RemoteException rx = new RemoteException("Activation failed.");
rx.detail = exc;
throw rx;
}
}
/**
* If the object is not active, activate it first.
*/
public Object incomingMessageCall(UnicastConnection conn, int method,
long hash) throws Exception
{
if (myself == null)
activate();
return super.incomingMessageCall(conn, method, hash);
}
/**
* Export object and ensure it is present in the server activation table
* as well.
*/
public Remote exportObject(Remote obj) throws RemoteException
{
Remote r = super.exportObject(obj);
UnicastServer.registerActivatable(this);
return r;
}
/**
* Export object and ensure it is present in the server activation table as
* well.
*
* @param aClass the class being exported, must implement Remote.
*/
public Remote exportClass(Class aClass) throws RemoteException
{
if (!Remote.class.isAssignableFrom(aClass))
throw new InternalError(aClass.getName()+" must implement Remote");
String ignoreStubs;
ClassLoader loader =aClass.getClassLoader();
// Stubs are always searched for the bootstrap classes that may have
// obsolete pattern and may still need also skeletons.
if (loader==null)
ignoreStubs = "false";
else
ignoreStubs = System.getProperty("java.rmi.server.ignoreStubClasses",
"false");
if (! ignoreStubs.equals("true"))
{
// Find and install the stub
Class cls = aClass;
// where ist the _Stub? (check superclasses also)
Class expCls = expCls = findStubSkelClass(cls);
if (expCls != null)
{
stub = (RemoteStub) getHelperClass(expCls, "_Stub");
// Find and install the skeleton (if there is one)
skel = (Skeleton) getHelperClass(expCls, "_Skel");
}
}
if (stub == null)
stub = createProxyStub(aClass, this);
// Build hash of methods which may be called.
buildMethodHash(aClass, true);
UnicastServer.registerActivatable(this);
return stub;
}
/**
* Get the referencing class.
*/
public String getRefClass(ObjectOutput out)
{
return "ActivatableRef";
}
/**
* Read the content from the input stream.
*/
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
super.readExternal(in);
actId = (ActivationID) in.readObject();
}
/**
* Write the content to the output stream.
*/
public void writeExternal(ObjectOutput out) throws IOException
{
super.writeExternal(out);
out.writeObject(actId);
}
}

View file

@ -77,8 +77,8 @@ public class CombinedClassLoader extends ClassLoader
while (iter.hasNext())
{
cl = iter.next();
if (!sLoaders.contains(cl))
sLoaders.add(iter.next());
if (cl!=null && !sLoaders.contains(cl))
sLoaders.add(cl);
}
loaders = new ClassLoader[sLoaders.size()];
@ -96,7 +96,7 @@ public class CombinedClassLoader extends ClassLoader
{
try
{
return findClass(name);
return loaders[i].loadClass(name);
}
catch (ClassNotFoundException e)
{
@ -106,20 +106,6 @@ public class CombinedClassLoader extends ClassLoader
return super.findClass(name);
}
/**
* Find the library with the given name
*/
protected String findLibrary(String name)
{
for (int i = 0; i < loaders.length; i++)
{
String lib = findLibrary(name);
if (lib != null)
return lib;
}
return super.findLibrary(name);
}
/**
* Find resource with the given name.
*/
@ -127,7 +113,7 @@ public class CombinedClassLoader extends ClassLoader
{
for (int i = 0; i < loaders.length; i++)
{
URL resource = findResource(name);
URL resource = loaders[i].getResource(name);
if (resource != null)
return resource;
}
@ -141,7 +127,7 @@ public class CombinedClassLoader extends ClassLoader
{
for (int i = 0; i < loaders.length; i++)
{
Enumeration resource = findResources(name);
Enumeration resource = loaders[i].getResources(name);
if (resource != null)
return resource;
}

View file

@ -310,6 +310,14 @@ private UnicastConnection getClientConnection() throws IOException {
return (conn);
}
/**
* Get the string representation, describing the connection.
*/
public String toString()
{
return serverName+":"+serverPort+" ("+serverobj+")";
}
/**
* Discard a connection when we're done with it - maybe it can be
* recycled.
@ -443,4 +451,12 @@ public boolean equals(Object obj) {
return (false);
}
/**
* Get the string representation, describing the connection.
*/
public String toString()
{
return host+":"+port+" ("+other+")";
}
}

View file

@ -1,5 +1,5 @@
/* UnicastRef.java --
Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005
Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 2006
Free Software Foundation, Inc.
This file is part of GNU Classpath.
@ -36,8 +36,11 @@ 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.rmi.server;
import gnu.java.rmi.dgc.LeaseRenewingTask;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@ -50,6 +53,7 @@ import java.lang.reflect.Method;
import java.rmi.ConnectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.dgc.Lease;
import java.rmi.server.ObjID;
import java.rmi.server.Operation;
import java.rmi.server.RMIClientSocketFactory;
@ -59,221 +63,462 @@ import java.rmi.server.RemoteRef;
import java.rmi.server.UID;
public class UnicastRef
implements RemoteRef, ProtocolConstants {
implements RemoteRef, ProtocolConstants
{
public ObjID objid;
UnicastConnectionManager manager;
/**
* Use serial version UID for iteroperability
*/
private static final long serialVersionUID = 1;
/**
* Used by serialization, and let subclass capable of having default constructor
*/
// must be public otherwise java.rmi.RemoteObject cannot instantiate this class
// -- iP
public UnicastRef() {
}
public ObjID objid;
public UnicastRef(ObjID objid, String host, int port, RMIClientSocketFactory csf) {
this(objid);
manager = UnicastConnectionManager.getInstance(host, port, csf);
}
UnicastConnectionManager manager;
public UnicastRef(ObjID objid) {
this.objid = objid;
}
/**
* Used by serialization, and let subclass capable of having default
* constructor
*/
// must be public otherwise java.rmi.RemoteObject cannot instantiate this
// class
// -- iP
public UnicastRef()
{
}
public Object invoke(Remote obj, Method method, Object[] params, long opnum) throws Exception {
// Check if client and server are in the same VM, then local call can be used to
public UnicastRef(ObjID objid, String host, int port,
RMIClientSocketFactory csf)
{
this(objid);
manager = UnicastConnectionManager.getInstance(host, port, csf);
}
public UnicastRef(ObjID objid)
{
this.objid = objid;
}
public Object invoke(Remote obj, Method method, Object[] params, long opnum)
throws Exception
{
// Check if client and server are in the same VM, then local call can be
// used to
// replace remote call, but it's somewhat violating remote semantic.
Object svrobj = manager.serverobj;
// Make sure that the server object is compatible. It could be loaded from a different
// Make sure that the server object is compatible. It could be loaded from a
// different
// classloader --iP
if(svrobj != null && method.getDeclaringClass().isInstance(svrobj)){
//local call
Object ret = null;
try{
ret = method.invoke(svrobj, params);
}catch(InvocationTargetException e){
throw (Exception)e.getTargetException();
}
//System.out.println("\n\n ***** local call: " + method + "\nreturn: " + ret + "\n\n");
return ret;
}
//System.out.println("***************** remote call:" + manager.serverPort);
return (invokeCommon(obj, method, params, -1, opnum));
}
if (svrobj != null && method.getDeclaringClass().isInstance(svrobj))
{
// local call
Object ret = null;
try
{
ret = method.invoke(svrobj, params);
}
catch (InvocationTargetException e)
{
throw (Exception) e.getTargetException();
}
// System.out.println("\n\n ***** local call: " + method + "\nreturn: "
// + ret + "\n\n");
return ret;
}
// System.out.println("***************** remote call:" +
// manager.serverPort);
return (invokeCommon(obj, method, params, - 1, opnum));
}
private Object invokeCommon(Remote obj, Method method, Object[] params, int opnum, long hash) throws Exception {
UnicastConnection conn;
try {
conn = manager.getConnection();
}
catch (IOException e1) {
throw new RemoteException("connection failed to host: " + manager.serverName, e1);
}
/**
* The ordinary number of the DGC messages.
*/
static long dgcSequence;
ObjectOutputStream out;
DataOutputStream dout;
try {
dout = conn.getDataOutputStream();
dout.writeByte(MESSAGE_CALL);
/**
* The DGC object id, also serves as a synchronization target to increment the
* dgcSequence safely.
*/
static final ObjID dgcId = new ObjID(ObjID.DGC_ID);
out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
objid.write(out);
out.writeInt(opnum);
out.writeLong(hash);
// must handle primitive class and their wrapper classes
Class clss[] = method.getParameterTypes();
for(int i = 0; i < clss.length; i++)
((RMIObjectOutputStream)out).writeValue(params[i], clss[i]);
ObjID[] this_id;
out.flush();
}
catch (IOException e2) {
throw new RemoteException("call failed: ", e2);
}
/**
* The number of the method "dirty" in the DGC.
*/
static int DIRTY = 1;
int returncode;
Object returnval;
DataInputStream din;
ObjectInputStream in;
UID ack;
try {
din = conn.getDataInputStream();
if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK) {
conn.disconnect();
throw new RemoteException("Call not acked:" + returncode);
}
/**
* The DGC interface hash code.
*/
static final long dgcInterfaceHash = - 669196253586618813L;
in = conn.startObjectInputStream(); // (re)start ObjectInputStream
returncode = in.readUnsignedByte();
ack = UID.read(in);
/**
* Notify the DGC of the remote side that we still hold this object.
*/
public Lease notifyDGC(Lease lease) throws Exception
{
long seq;
synchronized (dgcId)
{
seq = dgcSequence++;
}
Class cls = method.getReturnType();
if (this_id == null)
this_id = new ObjID[] { objid };
if (returncode == RETURN_NACK) {
returnval = in.readObject(); // get Exception
} else if(cls == Void.TYPE) {
returnval = null;
// in.readObject() // not required! returntype 'void' means no field is returned.
} else {
returnval = ((RMIObjectInputStream)in).readValue(cls); // get returnvalue
}
} catch (IOException e3) {
//for debug: e3.printStackTrace();
throw new RemoteException("call return failed: ", e3);
}
/* if DGCAck is necessary??
//According to RMI wire protocol, send a DGCAck
// to indicate receiving return value
dout.writeByte(MESSAGE_DGCACK);
ack.write(dout);
out.flush();
*/
manager.discardConnection(conn);
if (returncode != RETURN_ACK && returnval != null) {
if (returncode == RETURN_NACK) throw (Exception)returnval;
else throw new RemoteException("unexpected returncode: " + returncode);
}
return (returnval);
}
/**
* @deprecated
*/
public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, long hash) throws RemoteException {
UnicastConnection conn;
try {
conn = manager.getConnection();
}
catch (IOException e1) {
throw new ConnectException("connection failed to host: " + manager.serverName, e1);
}
try
{
conn = manager.getConnection();
}
catch (IOException e1)
{
throw new RemoteException("connection failed to host: "
+ manager.serverName, e1);
}
//obj: useless?
ObjectOutputStream out;
DataOutputStream dout;
try
{
dout = conn.getDataOutputStream();
dout.writeByte(MESSAGE_CALL);
return (new UnicastRemoteCall(conn, objid, opnum, hash));
}
out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
/**
* @deprecated
*/
public void invoke(RemoteCall call) throws Exception {
UnicastRemoteCall c = (UnicastRemoteCall)call;
call.executeCall();
}
dgcId.write(out);
// The number of the operation is 1 ("dirty")
out.writeInt(DIRTY);
out.writeLong(dgcInterfaceHash);
/**
* @deprecated
*/
public void done(RemoteCall call) throws RemoteException {
UnicastRemoteCall c = (UnicastRemoteCall)call;
try{
c.done();
} catch(IOException e){}
RMIObjectOutputStream rout = (RMIObjectOutputStream) out;
rout.writeValue(this_id, this_id.getClass());
rout.writeLong(seq);
rout.writeValue(lease, lease.getClass());
out.flush();
}
catch (IOException e2)
{
throw new RemoteException("DGC call failed: ", e2);
}
int returncode;
Object returnval;
DataInputStream din;
ObjectInputStream in;
UID ack;
try
{
din = conn.getDataInputStream();
if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK)
{
conn.disconnect();
throw new RemoteException("DGC Call not acked:" + returncode);
}
in = conn.startObjectInputStream(); // (re)start ObjectInputStream
returncode = in.readUnsignedByte();
ack = UID.read(in);
if (returncode == RETURN_NACK)
{
returnval = in.readObject(); // get Exception
}
else
{
returnval = ((RMIObjectInputStream) in).readValue(Lease.class);
}
}
catch (IOException e3)
{
throw new RemoteException("DGC call return failed: ", e3);
}
manager.discardConnection(conn);
if (returncode != RETURN_ACK && returnval != null)
{
if (returncode == RETURN_NACK)
throw (Exception) returnval;
else
throw new RemoteException("DGC unexpected returncode: " + returncode);
}
return (Lease) returnval;
}
/**
* Invoke the remote method on the given object. This part is overridden by
* the activatable objects.
*/
protected Object invokeCommon(Remote obj, Method method, Object[] params,
int opnum, long hash) throws Exception
{
UnicastConnection conn;
try
{
conn = manager.getConnection();
return invokeCommon(conn, obj, method, params, opnum, hash);
}
catch (IOException e1)
{
throw new RemoteException("connection failed to host: "
+ manager.serverName, e1);
}
}
/**
* Invoke the remote method on the given object when connection is already
* established.
*/
protected Object invokeCommon(UnicastConnection conn, Remote obj,
Method method, Object[] params, int opnum,
long hash) throws Exception
{
ObjectOutputStream out;
DataOutputStream dout;
try
{
dout = conn.getDataOutputStream();
dout.writeByte(MESSAGE_CALL);
out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
objid.write(out);
out.writeInt(opnum);
out.writeLong(hash);
// must handle primitive class and their wrapper classes
Class clss[] = method.getParameterTypes();
for (int i = 0; i < clss.length; i++)
((RMIObjectOutputStream) out).writeValue(params[i], clss[i]);
out.flush();
}
catch (IOException e2)
{
throw new RemoteException("call failed: ", e2);
}
int returncode;
Object returnval;
DataInputStream din;
ObjectInputStream in;
UID ack;
try
{
din = conn.getDataInputStream();
if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK)
{
conn.disconnect();
throw new RemoteException("Call not acked:" + returncode);
}
in = conn.startObjectInputStream(); // (re)start ObjectInputStream
returncode = in.readUnsignedByte();
ack = UID.read(in);
Class cls = method.getReturnType();
if (returncode == RETURN_NACK)
{
returnval = in.readObject(); // get Exception
}
else if (cls == Void.TYPE)
{
returnval = null;
// in.readObject() // not required! returntype 'void' means no field
// is returned.
}
else
{
returnval = ((RMIObjectInputStream) in).readValue(cls); // get
// returnvalue
}
}
catch (IOException e3)
{
// for debug: e3.printStackTrace();
throw new RemoteException("call return failed: ", e3);
}
/*
* if DGCAck is necessary?? //According to RMI wire protocol, send a DGCAck //
* to indicate receiving return value dout.writeByte(MESSAGE_DGCACK);
* ack.write(dout); out.flush();
*/
manager.discardConnection(conn);
if (returncode != RETURN_ACK && returnval != null)
{
if (returncode == RETURN_NACK)
throw (Exception) returnval;
else
throw new RemoteException("unexpected returncode: " + returncode);
}
return (returnval);
}
/**
* @deprecated
*/
public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum,
long hash) throws RemoteException
{
UnicastConnection conn;
try
{
conn = manager.getConnection();
}
catch (IOException e1)
{
throw new ConnectException("connection failed to host: "
+ manager.serverName, e1);
}
// obj: useless?
return (new UnicastRemoteCall(conn, objid, opnum, hash));
}
/**
* @deprecated
*/
public void invoke(RemoteCall call) throws Exception
{
UnicastRemoteCall c = (UnicastRemoteCall) call;
call.executeCall();
}
/**
* @deprecated
*/
public void done(RemoteCall call) throws RemoteException
{
UnicastRemoteCall c = (UnicastRemoteCall) call;
try
{
c.done();
}
catch (IOException e)
{
}
UnicastConnection conn = c.getConnection();
manager.discardConnection(conn);
}
manager.discardConnection(conn);
}
public void writeExternal(ObjectOutput out) throws IOException {
if (manager == null) {
throw new IOException("no connection");
}
manager.write(out);
objid.write(out);
// This byte is somewhat confusing when interoperating with JDK
out.writeByte(0); //RETURN_ACK);
}
public void writeExternal(ObjectOutput out) throws IOException
{
if (manager == null)
{
throw new IOException("no connection");
}
manager.write(out);
objid.write(out);
// This byte is somewhat confusing when interoperating with JDK
out.writeByte(0); // RETURN_ACK);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
manager = UnicastConnectionManager.read(in);
objid = ObjID.read(in);
byte ack = in.readByte();
// This byte is somewhat confusing when interoperating with JDK
if (ack != RETURN_ACK && ack != 0/*jdk ack value*/) {
throw new IOException("no ack found");
}
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException
{
manager = UnicastConnectionManager.read(in);
objid = ObjID.read(in);
byte ack = in.readByte();
// This byte is somewhat confusing when interoperating with JDK
if (ack != RETURN_ACK && ack != 0/* jdk ack value */)
{
throw new IOException("no ack found");
}
public boolean remoteEquals(RemoteRef ref) {
throw new Error("Not implemented");
}
// Notify the DGC of the remote side that we hold the reference to the
// received object. Do not notify if the client and server are on the
// same virtual machine.
if (manager.serverobj == null)
LeaseRenewingTask.scheduleLeases(this);
}
public int remoteHashCode() {
throw new Error("Not implemented");
}
public boolean remoteEquals(RemoteRef ref)
{
throw new Error("Not implemented");
}
public String getRefClass(ObjectOutput out) {
return ("UnicastRef");
}
public int remoteHashCode()
{
throw new Error("Not implemented");
}
public String remoteToString() {
throw new Error("Not implemented");
}
public String getRefClass(ObjectOutput out)
{
return ("UnicastRef");
}
/**
* Return the string representing the remote reference information.
*/
public String remoteToString()
{
if (manager!=null)
return manager.toString();
else
return "null manager";
}
public void dump(UnicastConnection conn) {
try {
DataInputStream din = conn.getDataInputStream();
for (;;) {
int b = din.readUnsignedByte();
System.out.print(Integer.toHexString(b));
if (b >= 32 && b < 128) {
System.out.print(": " + (char)b);
}
System.out.println();
}
}
catch (IOException _) {
}
}
public void dump(UnicastConnection conn)
{
try
{
DataInputStream din = conn.getDataInputStream();
for (;;)
{
int b = din.readUnsignedByte();
System.out.print(Integer.toHexString(b));
if (b >= 32 && b < 128)
{
System.out.print(": " + (char) b);
}
System.out.println();
}
}
catch (IOException _)
{
}
}
/**
* Check if this UnicastRef points to the object as the passed UnicastRef.
* Both the object Id and manager must be the same.
*
* @return true if the passed reference points to the same remote object as
* this reference, false otherwise.
*/
public boolean equals(Object other)
{
if (other instanceof UnicastRef)
{
UnicastRef r = (UnicastRef) other;
return r.manager.equals(manager) && r.objid.equals(objid);
}
else
return false;
}
/**
* Get the hash code of this UnicastRef, combining hash code of the manager
* with hash code of the object id.
*/
public int hashCode()
{
return manager.hashCode() ^ objid.hashCode();
}
}

View file

@ -40,6 +40,7 @@ exception statement from your version. */
package gnu.java.rmi.server;
import gnu.java.rmi.dgc.DGCImpl;
import gnu.java.util.WeakIdentityHashMap;
import java.io.DataOutputStream;
import java.io.IOException;
@ -49,122 +50,272 @@ import java.rmi.NoSuchObjectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.ServerError;
import java.rmi.activation.ActivationException;
import java.rmi.activation.ActivationID;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Hashtable;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.WeakHashMap;
public class UnicastServer
implements ProtocolConstants {
implements ProtocolConstants
{
static private Hashtable objects = new Hashtable(); //mapping OBJID to server ref
static private Map refcache = Collections.synchronizedMap(new IdentityHashMap()); //mapping obj itself to server ref
static private DGCImpl dgc;
/**
* Mapping OBJID to server ref by .equals().
*/
static private Map objects = Collections.synchronizedMap(new WeakHashMap());
public static void exportObject(UnicastServerRef obj) {
startDGC();
objects.put(obj.objid, obj);
refcache.put(obj.myself, obj);
obj.manager.startServer();
}
/**
* Mapping obj itself to server ref by identity.
*/
static private Map refcache = Collections.synchronizedMap(new WeakIdentityHashMap());
/**
* Mapping the registered activatable objects into they server references.
*/
public static Map actIds = new Hashtable();
/**
* The reference to the local distributed garbage collector.
*/
static private DGCImpl dgc;
/**
* Connect this server reference to the server, allowing the local
* implementation, associated with this object, to receive remote calls.
*
* @param obj the server reference, encloses the (usually local) remote
* object.
*/
public static void exportObject(UnicastServerRef obj)
{
startDGC();
objects.put(obj.objid, obj);
refcache.put(obj.myself, obj);
obj.manager.startServer();
}
/**
* Register the activatable object into the table of the activatable
* objects.
*/
public static void registerActivatable(ActivatableServerRef ref)
{
actIds.put(ref.actId, ref);
}
/**
* Export tha activatable object. The object id is placed into the map,
* but the object itself not. This is enough to deliver call to
* the ref.incomingMessageCall where the object will be instantiated,
* if not present.
*/
public static void exportActivatableObject(ActivatableServerRef ref)
{
startDGC();
objects.put(ref.objid, ref);
ref.manager.startServer();
actIds.put(ref.actId, ref);
}
/**
* Get the activatable server reference that is handling activation of the
* given activation id.
*/
public static ActivatableServerRef getActivatableRef(ActivationID id)
throws ActivationException
{
ActivatableServerRef ref = (ActivatableServerRef) actIds.get(id);
if (ref == null)
throw new ActivationException(id + " was not registered with this server");
return ref;
}
/**
* Unregister the previously registered activatable server reference.
*/
public static void unregisterActivatable(ActivationID id)
{
actIds.remove(id);
}
// FIX ME: I haven't handle force parameter
/**
* Remove the given server reference. The remote object, associated with
* this reference, will no longer receive remote calls via this server.
*/
public static boolean unexportObject(UnicastServerRef obj, boolean force)
{
objects.remove(obj.objid);
refcache.remove(obj.myself);
obj.manager.stopServer();
if (obj instanceof ActivatableServerRef)
{
ActivationID id = ((ActivatableServerRef) obj).actId;
unregisterActivatable(id);
}
return true;
}
/**
* Get the exported reference of the given Remote. The identity map is used,
* the non-null value will only be returned if exactly the passed remote
* is part of the registered UnicastServerRef.
*
* @param remote the Remote that is connected to this server via
* {@link UnicastServerRef}.
*
* @return the UnicastServerRef that is used to connect the passed
* remote with this server or null, if this Remote is not connected
* to this server.
*/
public static UnicastServerRef getExportedRef(Remote remote)
{
return (UnicastServerRef) refcache.get(remote);
}
// FIX ME: I haven't handle force parameter
public static boolean unexportObject(UnicastServerRef obj, boolean force) {
objects.remove(obj.objid);
refcache.remove(obj.myself);
obj.manager.stopServer();
return true;
}
/**
* Get the server references to the object, previously exported via this
* server. As the identity map is scanned, more than one reference may match
* this Id.
*
* @param id the id of the exported object
* @return the server reference to this object, null if none.
*/
public static Collection getExported(Object id)
{
synchronized (objects)
{
ArrayList list = new ArrayList();
Iterator iter = objects.entrySet().iterator();
Map.Entry e;
Object key;
while (iter.hasNext())
{
e = (Map.Entry) iter.next();
key = e.getKey();
if (key != null && key.equals(id))
list.add(e.getValue());
}
return list;
}
}
public static UnicastServerRef getExportedRef(Remote remote){
return (UnicastServerRef)refcache.get(remote);
}
private static synchronized void startDGC()
{
if (dgc == null)
{
try
{
dgc = new DGCImpl();
// Changed DGCImpl to inherit UnicastServerRef directly
// ((UnicastServerRef)dgc.getRef()).exportObject(dgc);
dgc.exportObject(dgc);
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
}
private static synchronized void startDGC() {
if (dgc == null) {
try {
dgc = new DGCImpl();
// Changed DGCImpl to inherit UnicastServerRef directly
//((UnicastServerRef)dgc.getRef()).exportObject(dgc);
dgc.exportObject(dgc);
}
catch (RemoteException e) {
e.printStackTrace();
}
}
}
public static void dispatch(UnicastConnection conn) throws Exception
{
switch (conn.getDataInputStream().readUnsignedByte())
{
case MESSAGE_CALL:
incomingMessageCall(conn);
break;
case MESSAGE_PING:
// jdk sends a ping before each method call -> answer it!
DataOutputStream out = conn.getDataOutputStream();
out.writeByte(MESSAGE_PING_ACK);
out.flush();
break;
default:
throw new Exception("bad method type");
}
}
/**
* This method is invoked when the remote call is received. The method
* dispatches the call to the responsible object, connected to this
* server via UnicastServerReference.
*/
private static void incomingMessageCall(UnicastConnection conn)
throws IOException
{
ObjectInputStream in = conn.startObjectInputStream(); // (re)start
// ObjectInputStream
public static void dispatch(UnicastConnection conn) throws Exception {
switch (conn.getDataInputStream().readUnsignedByte()) {
case MESSAGE_CALL:
incomingMessageCall(conn);
break;
case MESSAGE_PING:
// jdk sends a ping before each method call -> answer it!
DataOutputStream out = conn.getDataOutputStream();
out.writeByte(MESSAGE_PING_ACK);
out.flush();
break;
default:
throw new Exception("bad method type");
}
}
ObjID objid = ObjID.read(in);
int method = in.readInt();
long hash = in.readLong();
private static void incomingMessageCall(UnicastConnection conn) throws IOException {
ObjectInputStream in = conn.startObjectInputStream(); // (re)start ObjectInputStream
// System.out.println("ObjID: " + objid + ", method: " + method + ", hash: "
// + hash);
ObjID objid = ObjID.read(in);
int method = in.readInt();
long hash = in.readLong();
// Use the objid to locate the relevant UnicastServerRef
UnicastServerRef uref = (UnicastServerRef) objects.get(objid);
Object returnval;
int returncode = RETURN_ACK;
// returnval is from Method.invoke(), so we must check the return class to
// see
// if it's primitive type
Class returncls = null;
if (uref != null)
{
try
{
// Dispatch the call to it.
returnval = uref.incomingMessageCall(conn, method, hash);
returncls = uref.getMethodReturnType(method, hash);
}
catch (Exception e)
{
returnval = e;
returncode = RETURN_NACK;
}
catch (Error e)
{
returnval = new ServerError(
"Server error, ObjID: " + objid +
", method: " + method + ", hash: "+ hash, e);
returncode = RETURN_NACK;
}
}
else
{
returnval = new NoSuchObjectException("ObjID: " + objid);
returncode = RETURN_NACK;
}
//System.out.println("ObjID: " + objid + ", method: " + method + ", hash: " + hash);
conn.getDataOutputStream().writeByte(MESSAGE_CALL_ACK);
// Use the objid to locate the relevant UnicastServerRef
UnicastServerRef uref = (UnicastServerRef)objects.get(objid);
Object returnval;
int returncode = RETURN_ACK;
// returnval is from Method.invoke(), so we must check the return class to see
// if it's primitive type
Class returncls = null;
if (uref != null) {
try {
// Dispatch the call to it.
returnval = uref.incomingMessageCall(conn, method, hash);
returncls = uref.getMethodReturnType(method, hash);
}
catch (Exception e) {
returnval = e;
returncode = RETURN_NACK;
}
catch (Error e) {
returnval = new ServerError ("An Error is thrown while processing the invocation on the server", e);
returncode = RETURN_NACK;
}
}
else {
returnval = new NoSuchObjectException("");
returncode = RETURN_NACK;
}
ObjectOutputStream out = conn.startObjectOutputStream(); // (re)start
// ObjectOutputStream
conn.getDataOutputStream().writeByte(MESSAGE_CALL_ACK);
out.writeByte(returncode);
(new UID()).write(out);
ObjectOutputStream out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream
// System.out.println("returnval=" + returnval + " returncls=" + returncls);
out.writeByte(returncode);
(new UID()).write(out);
if (returnval != null && returncls != null)
((RMIObjectOutputStream) out).writeValue(returnval, returncls);
//System.out.println("returnval=" + returnval + " returncls=" + returncls);
// 1.1/1.2 void return type detection:
else if (! (returnval instanceof RMIVoidValue || returncls == Void.TYPE))
out.writeObject(returnval);
if(returnval != null && returncls != null)
((RMIObjectOutputStream)out).writeValue(returnval, returncls);
// 1.1/1.2 void return type detection:
else if (!(returnval instanceof RMIVoidValue || returncls == Void.TYPE))
out.writeObject(returnval);
out.flush();
}
out.flush();
}
}

View file

@ -58,6 +58,10 @@ import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
/**
* This class connects the local, remotely available (exported) object to
* the local RMI server that accepts the remote calls.
*/
public class UnicastServerRef
extends UnicastRef
{
@ -80,18 +84,18 @@ public class UnicastServerRef
/**
* The skeleton (if any), associated with the exported remote object.
*/
private Skeleton skel;
protected Skeleton skel;
/**
* The stub, associated with the exported remote object (may be proxy class).
*/
private Remote stub;
protected Remote stub;
/**
* The method table (RMI hash code to method) of the methods of the
* exported object.
*/
private Hashtable methods = new Hashtable();
protected Hashtable methods = new Hashtable();
/**
* Used by serialization.
@ -125,8 +129,7 @@ public class UnicastServerRef
{
myself = obj;
// Save it to server manager, to let client calls in the same VM to
// issue
// local call
// issue local call
manager.serverobj = obj;
String ignoreStubs;
@ -202,7 +205,7 @@ public class UnicastServerRef
*
* @return the class having stub defined, null if none.
*/
private Class findStubSkelClass(Class startCls)
protected Class findStubSkelClass(Class startCls)
{
Class cls = startCls;
@ -242,7 +245,7 @@ public class UnicastServerRef
* @return the instantiated instance of the helper class or null if the
* helper class cannot be found or instantiated.
*/
private Object getHelperClass(Class cls, String type)
protected Object getHelperClass(Class cls, String type)
{
try
{
@ -310,7 +313,7 @@ public class UnicastServerRef
* @param build if true, the class methods are added to the table. If
* false, they are removed from the table.
*/
private void buildMethodHash(Class cls, boolean build)
protected void buildMethodHash(Class cls, boolean build)
{
Method[] meths = cls.getMethods();
for (int i = 0; i < meths.length; i++)
@ -339,7 +342,11 @@ public class UnicastServerRef
else
return null;
}
/**
* This method is called from the {@link UnicastServer#incomingMessageCall}
* to deliver the remote call to this object.
*/
public Object incomingMessageCall(UnicastConnection conn, int method,
long hash) throws Exception
{
@ -353,7 +360,8 @@ public class UnicastServerRef
// meth);
if (meth == null)
{
throw new NoSuchMethodException();
throw new NoSuchMethodException(
myself.getClass().getName()+" hash "+hash);
}
ObjectInputStream in = conn.getObjectInputStream();
@ -413,9 +421,8 @@ public class UnicastServerRef
else
{
if (skel == null)
{
throw new NoSuchMethodException();
}
throw new NoSuchMethodException("JDK 1.1 call - Skeleton required");
UnicastRemoteCall call = new UnicastRemoteCall(conn);
skel.dispatch(myself, call, method, hash);
if (! call.isReturnValue())

View file

@ -333,9 +333,9 @@ public final class Properties
handleBooleanProperty(DO_RSA_BLINDING);
// re-sync the 'known' properties
reproducible = new Boolean((String) props.get(REPRODUCIBLE_PRNG)).booleanValue();
checkForWeakKeys = new Boolean((String) props.get(CHECK_WEAK_KEYS)).booleanValue();
doRSABlinding = new Boolean((String) props.get(DO_RSA_BLINDING)).booleanValue();
reproducible = Boolean.valueOf((String) props.get(REPRODUCIBLE_PRNG)).booleanValue();
checkForWeakKeys = Boolean.valueOf((String) props.get(CHECK_WEAK_KEYS)).booleanValue();
doRSABlinding = Boolean.valueOf((String) props.get(DO_RSA_BLINDING)).booleanValue();
// This does not change.
props.put(VERSION, Registry.VERSION_STRING);

View file

@ -159,6 +159,9 @@ public interface Registry
// Padding scheme names and synonyms........................................
/** PKCS#5 padding scheme. */
String PKCS5_PAD = "pkcs5";
/** PKCS#7 padding scheme. */
String PKCS7_PAD = "pkcs7";

View file

@ -567,7 +567,7 @@ public class Haval extends BaseHash
{
if (valid == null)
{
valid = new Boolean(DIGEST0.equals(Util.toString(new Haval().digest())));
valid = Boolean.valueOf(DIGEST0.equals(Util.toString(new Haval().digest())));
}
return valid.booleanValue();
}

View file

@ -181,7 +181,7 @@ public class MD2 extends BaseHash
{
if (valid == null)
{
valid = new Boolean(DIGEST0.equals(Util.toString(new MD2().digest())));
valid = Boolean.valueOf(DIGEST0.equals(Util.toString(new MD2().digest())));
}
return valid.booleanValue();
}

View file

@ -154,7 +154,7 @@ public class MD4 extends BaseHash
{
if (valid == null)
{
valid = new Boolean(DIGEST0.equals(Util.toString(new MD4().digest())));
valid = Boolean.valueOf(DIGEST0.equals(Util.toString(new MD4().digest())));
}
return valid.booleanValue();
}

View file

@ -358,7 +358,7 @@ public class MD5 extends BaseHash
{
if (valid == null)
{
valid = new Boolean(DIGEST0.equals(Util.toString(new MD5().digest())));
valid = Boolean.valueOf(DIGEST0.equals(Util.toString(new MD5().digest())));
}
return valid.booleanValue();
}

View file

@ -283,7 +283,7 @@ public class RipeMD128 extends BaseHash
{
if (valid == null)
{
valid = new Boolean
valid = Boolean.valueOf
(DIGEST0.equals(Util.toString(new RipeMD128().digest())));
}
return valid.booleanValue();

View file

@ -320,7 +320,7 @@ public class RipeMD160 extends BaseHash
{
if (valid == null)
{
valid = new Boolean
valid = Boolean.valueOf
(DIGEST0.equals(Util.toString(new RipeMD160().digest())));
}
return valid.booleanValue();

View file

@ -229,7 +229,7 @@ public class Sha160 extends BaseHash
md.update((byte) 0x62); // b
md.update((byte) 0x63); // c
String result = Util.toString(md.digest());
valid = new Boolean(DIGEST0.equals(result));
valid = Boolean.valueOf(DIGEST0.equals(result));
}
return valid.booleanValue();
}

View file

@ -217,7 +217,7 @@ public class Sha256 extends BaseHash
md.update((byte) 0x62); // b
md.update((byte) 0x63); // c
String result = Util.toString(md.digest());
valid = new Boolean(DIGEST0.equals(result));
valid = Boolean.valueOf(DIGEST0.equals(result));
}
return valid.booleanValue();

View file

@ -254,7 +254,7 @@ public class Sha384 extends BaseHash
md.update((byte) 0x62); // b
md.update((byte) 0x63); // c
String result = Util.toString(md.digest());
valid = new Boolean(DIGEST0.equals(result));
valid = Boolean.valueOf(DIGEST0.equals(result));
}
return valid.booleanValue();
}

View file

@ -256,7 +256,7 @@ public class Sha512 extends BaseHash
md.update((byte) 0x62); // b
md.update((byte) 0x63); // c
String result = Util.toString(md.digest());
valid = new Boolean(DIGEST0.equals(result));
valid = Boolean.valueOf(DIGEST0.equals(result));
}
return valid.booleanValue();
}

View file

@ -640,7 +640,7 @@ public class Tiger extends BaseHash
{
if (valid == null)
{
valid = new Boolean(DIGEST0.equals(Util.toString(new Tiger().digest())));
valid = Boolean.valueOf(DIGEST0.equals(Util.toString(new Tiger().digest())));
}
return valid.booleanValue();
}

View file

@ -42,25 +42,25 @@ import gnu.java.security.Registry;
import gnu.java.security.util.Util;
/**
* <p>Whirlpool, a new 512-bit hashing function operating on messages less than
* Whirlpool, a new 512-bit hashing function operating on messages less than
* 2 ** 256 bits in length. The function structure is designed according to the
* Wide Trail strategy and permits a wide variety of implementation trade-offs.
* </p>
*
* <p><b>IMPORTANT</b>: This implementation is not thread-safe.</p>
*
* <p>References:</p>
*
* <p>
* This implementation is of Whirlpool Version 3, described in [1] last revised
* on May 24th, 2003.
* <p>
* <b>IMPORTANT</b>: This implementation is not thread-safe.
* <p>
* References:
* <ol>
* <li><a href="http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html">
* The WHIRLPOOL Hashing Function</a>.<br>
* <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and
* <a href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
* <a href="mailto:vincent.rijmen@iaik.tugraz.at">Vincent Rijmen</a>.</li>
* </ol>
*/
public final class Whirlpool extends BaseHash
{
// Debugging methods and variables
// -------------------------------------------------------------------------
@ -74,45 +74,43 @@ public final class Whirlpool extends BaseHash
private static final int BLOCK_SIZE = 64; // inner block size in bytes
/** The digest of the 0-bit long message. */
private static final String DIGEST0 = "470F0409ABAA446E49667D4EBE12A14387CEDBD10DD17B8243CAD550A089DC0F"
+ "EEA7AA40F6C2AAAB71C6EBD076E43C7CFCA0AD32567897DCB5969861049A0F5A";
private static final String DIGEST0 =
"19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A7"
+ "3E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3";
private static final int R = 10; // default number of rounds
/** Default number of rounds. */
private static final int R = 10;
private static final String Sd = // p. 19 [WHIRLPOOL]
"\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152"
+ "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57"
+ "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85"
+ "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8"
+ "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333"
+ "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0"
+ "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE"
+ "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d"
+ "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF"
+ "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A"
+ "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c"
+ "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04"
+ "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB"
+ "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9"
+ "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1"
+ "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886";
/** Whirlpool S-box; p. 19. */
private static final String S_box = // p. 19 [WHIRLPOOL]
"\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152" +
"\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57" +
"\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85" +
"\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8" +
"\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333" +
"\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0" +
"\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE" +
"\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d" +
"\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF" +
"\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A" +
"\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c" +
"\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04" +
"\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB" +
"\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9" +
"\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1" +
"\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886";
/** The 64-bit lookup tables; section 7.1 p. 13. */
private static final long[] T0 = new long[256];
private static final long[] T1 = new long[256];
private static final long[] T2 = new long[256];
private static final long[] T3 = new long[256];
private static final long[] T4 = new long[256];
private static final long[] T5 = new long[256];
private static final long[] T6 = new long[256];
private static final long[] T7 = new long[256];
/** The round constants. */
private static final long[] rc = new long[R];
/** caches the result of the correctness test, once executed. */
@ -123,12 +121,10 @@ public final class Whirlpool extends BaseHash
/** Work area for computing the round key schedule. */
private long k00, k01, k02, k03, k04, k05, k06, k07;
private long Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7;
/** work area for transforming the 512-bit buffer. */
private long n0, n1, n2, n3, n4, n5, n6, n7;
private long nn0, nn1, nn2, nn3, nn4, nn5, nn6, nn7;
/** work area for holding block cipher's intermediate values. */
@ -140,72 +136,67 @@ public final class Whirlpool extends BaseHash
{
long time = System.currentTimeMillis();
int ROOT = 0x11d; // para. 2.1 [WHIRLPOOL]
int ROOT = 0x11D; // para. 2.1 [WHIRLPOOL]
int i, r, j;
long s, s2, s3, s4, s5, s8, s9, t;
long s1, s2, s4, s5, s8, s9, t;
char c;
final byte[] S = new byte[256];
for (i = 0; i < 256; i++)
{
c = Sd.charAt(i >>> 1);
c = S_box.charAt(i >>> 1);
s = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL;
s2 = s << 1;
s1 = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL;
s2 = s1 << 1;
if (s2 > 0xFFL)
{
s2 ^= ROOT;
}
s3 = s2 ^ s;
s2 ^= ROOT;
s4 = s2 << 1;
if (s4 > 0xFFL)
{
s4 ^= ROOT;
}
s5 = s4 ^ s;
s4 ^= ROOT;
s5 = s4 ^ s1;
s8 = s4 << 1;
if (s8 > 0xFFL)
{
s8 ^= ROOT;
}
s9 = s8 ^ s;
s8 ^= ROOT;
S[i] = (byte) s;
T0[i] = t = s << 56 | s << 48 | s3 << 40 | s << 32 | s5 << 24
| s8 << 16 | s9 << 8 | s5;
T1[i] = t >>> 8 | t << 56;
s9 = s8 ^ s1;
T0[i] = t = s1 << 56 | s1 << 48 | s4 << 40 | s1 << 32
| s8 << 24 | s5 << 16 | s2 << 8 | s9;
T1[i] = t >>> 8 | t << 56;
T2[i] = t >>> 16 | t << 48;
T3[i] = t >>> 24 | t << 40;
T4[i] = t >>> 32 | t << 32;
T5[i] = t >>> 40 | t << 24;
T6[i] = t >>> 48 | t << 16;
T7[i] = t >>> 56 | t << 8;
T7[i] = t >>> 56 | t << 8;
}
for (r = 1, i = 0, j = 0; r < R + 1; r++)
{
rc[i++] = (S[j++] & 0xFFL) << 56 | (S[j++] & 0xFFL) << 48
| (S[j++] & 0xFFL) << 40 | (S[j++] & 0xFFL) << 32
| (S[j++] & 0xFFL) << 24 | (S[j++] & 0xFFL) << 16
| (S[j++] & 0xFFL) << 8 | (S[j++] & 0xFFL);
}
for (r = 0, i = 0; r < R; )
rc[r++] = (T0[i++] & 0xFF00000000000000L)
^ (T1[i++] & 0x00FF000000000000L)
^ (T2[i++] & 0x0000FF0000000000L)
^ (T3[i++] & 0x000000FF00000000L)
^ (T4[i++] & 0x00000000FF000000L)
^ (T5[i++] & 0x0000000000FF0000L)
^ (T6[i++] & 0x000000000000FF00L)
^ (T7[i++] & 0x00000000000000FFL);
time = System.currentTimeMillis() - time;
if (DEBUG && debuglevel > 8)
{
System.out.println("==========");
System.out.println();
System.out.println("Static data");
System.out.println();
System.out.println();
System.out.println("T0[]:");
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T0[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T0[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -213,9 +204,8 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T1[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -223,9 +213,8 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T2[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -233,9 +222,8 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T3[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -243,9 +231,8 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T4[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -253,9 +240,8 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -263,9 +249,8 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
@ -273,17 +258,15 @@ public final class Whirlpool extends BaseHash
for (i = 0; i < 64; i++)
{
for (j = 0; j < 4; j++)
{
System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", ");
}
System.out.print("0x" + Util.toString(T5[i * 4 + j]) + ", ");
System.out.println();
}
System.out.println();
System.out.println("rc[]:");
for (i = 0; i < R; i++)
{
System.out.println("0x" + Util.toString(rc[i]));
}
System.out.println("0x" + Util.toString(rc[i]));
System.out.println();
System.out.println();
@ -340,38 +323,70 @@ public final class Whirlpool extends BaseHash
protected void transform(byte[] in, int offset)
{
// apply mu to the input
n0 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n1 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n2 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n3 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n4 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n5 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n6 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n7 = (in[offset++] & 0xFFL) << 56 | (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40 | (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24 | (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8 | (in[offset++] & 0xFFL);
n0 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n1 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n2 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n3 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n4 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n5 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n6 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
n7 = (in[offset++] & 0xFFL) << 56
| (in[offset++] & 0xFFL) << 48
| (in[offset++] & 0xFFL) << 40
| (in[offset++] & 0xFFL) << 32
| (in[offset++] & 0xFFL) << 24
| (in[offset++] & 0xFFL) << 16
| (in[offset++] & 0xFFL) << 8
| (in[offset++] & 0xFFL);
// transform K into the key schedule Kr; 0 <= r <= R
k00 = H0;
@ -399,62 +414,70 @@ public final class Whirlpool extends BaseHash
{
// 1. compute intermediate round key schedule by applying ro[rc]
// to the previous round key schedule --rc being the round constant
Kr0 = T0[(int) ((k00 >> 56) & 0xFFL)] ^ T1[(int) ((k07 >> 48) & 0xFFL)]
^ T2[(int) ((k06 >> 40) & 0xFFL)]
^ T3[(int) ((k05 >> 32) & 0xFFL)]
^ T4[(int) ((k04 >> 24) & 0xFFL)]
^ T5[(int) ((k03 >> 16) & 0xFFL)]
^ T6[(int) ((k02 >> 8) & 0xFFL)] ^ T7[(int) (k01 & 0xFFL)]
^ rc[r];
Kr1 = T0[(int) ((k01 >> 56) & 0xFFL)] ^ T1[(int) ((k00 >> 48) & 0xFFL)]
^ T2[(int) ((k07 >> 40) & 0xFFL)]
^ T3[(int) ((k06 >> 32) & 0xFFL)]
^ T4[(int) ((k05 >> 24) & 0xFFL)]
^ T5[(int) ((k04 >> 16) & 0xFFL)]
^ T6[(int) ((k03 >> 8) & 0xFFL)] ^ T7[(int) (k02 & 0xFFL)];
Kr2 = T0[(int) ((k02 >> 56) & 0xFFL)] ^ T1[(int) ((k01 >> 48) & 0xFFL)]
^ T2[(int) ((k00 >> 40) & 0xFFL)]
^ T3[(int) ((k07 >> 32) & 0xFFL)]
^ T4[(int) ((k06 >> 24) & 0xFFL)]
^ T5[(int) ((k05 >> 16) & 0xFFL)]
^ T6[(int) ((k04 >> 8) & 0xFFL)] ^ T7[(int) (k03 & 0xFFL)];
Kr3 = T0[(int) ((k03 >> 56) & 0xFFL)] ^ T1[(int) ((k02 >> 48) & 0xFFL)]
^ T2[(int) ((k01 >> 40) & 0xFFL)]
^ T3[(int) ((k00 >> 32) & 0xFFL)]
^ T4[(int) ((k07 >> 24) & 0xFFL)]
^ T5[(int) ((k06 >> 16) & 0xFFL)]
^ T6[(int) ((k05 >> 8) & 0xFFL)] ^ T7[(int) (k04 & 0xFFL)];
Kr4 = T0[(int) ((k04 >> 56) & 0xFFL)] ^ T1[(int) ((k03 >> 48) & 0xFFL)]
^ T2[(int) ((k02 >> 40) & 0xFFL)]
^ T3[(int) ((k01 >> 32) & 0xFFL)]
^ T4[(int) ((k00 >> 24) & 0xFFL)]
^ T5[(int) ((k07 >> 16) & 0xFFL)]
^ T6[(int) ((k06 >> 8) & 0xFFL)] ^ T7[(int) (k05 & 0xFFL)];
Kr5 = T0[(int) ((k05 >> 56) & 0xFFL)] ^ T1[(int) ((k04 >> 48) & 0xFFL)]
^ T2[(int) ((k03 >> 40) & 0xFFL)]
^ T3[(int) ((k02 >> 32) & 0xFFL)]
^ T4[(int) ((k01 >> 24) & 0xFFL)]
^ T5[(int) ((k00 >> 16) & 0xFFL)]
^ T6[(int) ((k07 >> 8) & 0xFFL)] ^ T7[(int) (k06 & 0xFFL)];
Kr6 = T0[(int) ((k06 >> 56) & 0xFFL)] ^ T1[(int) ((k05 >> 48) & 0xFFL)]
^ T2[(int) ((k04 >> 40) & 0xFFL)]
^ T3[(int) ((k03 >> 32) & 0xFFL)]
^ T4[(int) ((k02 >> 24) & 0xFFL)]
^ T5[(int) ((k01 >> 16) & 0xFFL)]
^ T6[(int) ((k00 >> 8) & 0xFFL)] ^ T7[(int) (k07 & 0xFFL)];
Kr7 = T0[(int) ((k07 >> 56) & 0xFFL)] ^ T1[(int) ((k06 >> 48) & 0xFFL)]
^ T2[(int) ((k05 >> 40) & 0xFFL)]
^ T3[(int) ((k04 >> 32) & 0xFFL)]
^ T4[(int) ((k03 >> 24) & 0xFFL)]
^ T5[(int) ((k02 >> 16) & 0xFFL)]
^ T6[(int) ((k01 >> 8) & 0xFFL)] ^ T7[(int) (k00 & 0xFFL)];
Kr0 = T0[(int)((k00 >> 56) & 0xFFL)]
^ T1[(int)((k07 >> 48) & 0xFFL)]
^ T2[(int)((k06 >> 40) & 0xFFL)]
^ T3[(int)((k05 >> 32) & 0xFFL)]
^ T4[(int)((k04 >> 24) & 0xFFL)]
^ T5[(int)((k03 >> 16) & 0xFFL)]
^ T6[(int)((k02 >> 8) & 0xFFL)]
^ T7[(int)( k01 & 0xFFL)] ^ rc[r];
Kr1 = T0[(int)((k01 >> 56) & 0xFFL)]
^ T1[(int)((k00 >> 48) & 0xFFL)]
^ T2[(int)((k07 >> 40) & 0xFFL)]
^ T3[(int)((k06 >> 32) & 0xFFL)]
^ T4[(int)((k05 >> 24) & 0xFFL)]
^ T5[(int)((k04 >> 16) & 0xFFL)]
^ T6[(int)((k03 >> 8) & 0xFFL)]
^ T7[(int)( k02 & 0xFFL)];
Kr2 = T0[(int)((k02 >> 56) & 0xFFL)]
^ T1[(int)((k01 >> 48) & 0xFFL)]
^ T2[(int)((k00 >> 40) & 0xFFL)]
^ T3[(int)((k07 >> 32) & 0xFFL)]
^ T4[(int)((k06 >> 24) & 0xFFL)]
^ T5[(int)((k05 >> 16) & 0xFFL)]
^ T6[(int)((k04 >> 8) & 0xFFL)]
^ T7[(int)( k03 & 0xFFL)];
Kr3 = T0[(int)((k03 >> 56) & 0xFFL)]
^ T1[(int)((k02 >> 48) & 0xFFL)]
^ T2[(int)((k01 >> 40) & 0xFFL)]
^ T3[(int)((k00 >> 32) & 0xFFL)]
^ T4[(int)((k07 >> 24) & 0xFFL)]
^ T5[(int)((k06 >> 16) & 0xFFL)]
^ T6[(int)((k05 >> 8) & 0xFFL)]
^ T7[(int)( k04 & 0xFFL)];
Kr4 = T0[(int)((k04 >> 56) & 0xFFL)]
^ T1[(int)((k03 >> 48) & 0xFFL)]
^ T2[(int)((k02 >> 40) & 0xFFL)]
^ T3[(int)((k01 >> 32) & 0xFFL)]
^ T4[(int)((k00 >> 24) & 0xFFL)]
^ T5[(int)((k07 >> 16) & 0xFFL)]
^ T6[(int)((k06 >> 8) & 0xFFL)]
^ T7[(int)( k05 & 0xFFL)];
Kr5 = T0[(int)((k05 >> 56) & 0xFFL)]
^ T1[(int)((k04 >> 48) & 0xFFL)]
^ T2[(int)((k03 >> 40) & 0xFFL)]
^ T3[(int)((k02 >> 32) & 0xFFL)]
^ T4[(int)((k01 >> 24) & 0xFFL)]
^ T5[(int)((k00 >> 16) & 0xFFL)]
^ T6[(int)((k07 >> 8) & 0xFFL)]
^ T7[(int)( k06 & 0xFFL)];
Kr6 = T0[(int)((k06 >> 56) & 0xFFL)]
^ T1[(int)((k05 >> 48) & 0xFFL)]
^ T2[(int)((k04 >> 40) & 0xFFL)]
^ T3[(int)((k03 >> 32) & 0xFFL)]
^ T4[(int)((k02 >> 24) & 0xFFL)]
^ T5[(int)((k01 >> 16) & 0xFFL)]
^ T6[(int)((k00 >> 8) & 0xFFL)]
^ T7[(int)( k07 & 0xFFL)];
Kr7 = T0[(int)((k07 >> 56) & 0xFFL)]
^ T1[(int)((k06 >> 48) & 0xFFL)]
^ T2[(int)((k05 >> 40) & 0xFFL)]
^ T3[(int)((k04 >> 32) & 0xFFL)]
^ T4[(int)((k03 >> 24) & 0xFFL)]
^ T5[(int)((k02 >> 16) & 0xFFL)]
^ T6[(int)((k01 >> 8) & 0xFFL)]
^ T7[(int)( k00 & 0xFFL)];
k00 = Kr0;
k01 = Kr1;
@ -466,54 +489,70 @@ public final class Whirlpool extends BaseHash
k07 = Kr7;
// 2. incrementally compute the cipher output
w0 = T0[(int) ((nn0 >> 56) & 0xFFL)] ^ T1[(int) ((nn7 >> 48) & 0xFFL)]
^ T2[(int) ((nn6 >> 40) & 0xFFL)]
^ T3[(int) ((nn5 >> 32) & 0xFFL)]
^ T4[(int) ((nn4 >> 24) & 0xFFL)]
^ T5[(int) ((nn3 >> 16) & 0xFFL)] ^ T6[(int) ((nn2 >> 8) & 0xFFL)]
^ T7[(int) (nn1 & 0xFFL)] ^ Kr0;
w1 = T0[(int) ((nn1 >> 56) & 0xFFL)] ^ T1[(int) ((nn0 >> 48) & 0xFFL)]
^ T2[(int) ((nn7 >> 40) & 0xFFL)]
^ T3[(int) ((nn6 >> 32) & 0xFFL)]
^ T4[(int) ((nn5 >> 24) & 0xFFL)]
^ T5[(int) ((nn4 >> 16) & 0xFFL)] ^ T6[(int) ((nn3 >> 8) & 0xFFL)]
^ T7[(int) (nn2 & 0xFFL)] ^ Kr1;
w2 = T0[(int) ((nn2 >> 56) & 0xFFL)] ^ T1[(int) ((nn1 >> 48) & 0xFFL)]
^ T2[(int) ((nn0 >> 40) & 0xFFL)]
^ T3[(int) ((nn7 >> 32) & 0xFFL)]
^ T4[(int) ((nn6 >> 24) & 0xFFL)]
^ T5[(int) ((nn5 >> 16) & 0xFFL)] ^ T6[(int) ((nn4 >> 8) & 0xFFL)]
^ T7[(int) (nn3 & 0xFFL)] ^ Kr2;
w3 = T0[(int) ((nn3 >> 56) & 0xFFL)] ^ T1[(int) ((nn2 >> 48) & 0xFFL)]
^ T2[(int) ((nn1 >> 40) & 0xFFL)]
^ T3[(int) ((nn0 >> 32) & 0xFFL)]
^ T4[(int) ((nn7 >> 24) & 0xFFL)]
^ T5[(int) ((nn6 >> 16) & 0xFFL)] ^ T6[(int) ((nn5 >> 8) & 0xFFL)]
^ T7[(int) (nn4 & 0xFFL)] ^ Kr3;
w4 = T0[(int) ((nn4 >> 56) & 0xFFL)] ^ T1[(int) ((nn3 >> 48) & 0xFFL)]
^ T2[(int) ((nn2 >> 40) & 0xFFL)]
^ T3[(int) ((nn1 >> 32) & 0xFFL)]
^ T4[(int) ((nn0 >> 24) & 0xFFL)]
^ T5[(int) ((nn7 >> 16) & 0xFFL)] ^ T6[(int) ((nn6 >> 8) & 0xFFL)]
^ T7[(int) (nn5 & 0xFFL)] ^ Kr4;
w5 = T0[(int) ((nn5 >> 56) & 0xFFL)] ^ T1[(int) ((nn4 >> 48) & 0xFFL)]
^ T2[(int) ((nn3 >> 40) & 0xFFL)]
^ T3[(int) ((nn2 >> 32) & 0xFFL)]
^ T4[(int) ((nn1 >> 24) & 0xFFL)]
^ T5[(int) ((nn0 >> 16) & 0xFFL)] ^ T6[(int) ((nn7 >> 8) & 0xFFL)]
^ T7[(int) (nn6 & 0xFFL)] ^ Kr5;
w6 = T0[(int) ((nn6 >> 56) & 0xFFL)] ^ T1[(int) ((nn5 >> 48) & 0xFFL)]
^ T2[(int) ((nn4 >> 40) & 0xFFL)]
^ T3[(int) ((nn3 >> 32) & 0xFFL)]
^ T4[(int) ((nn2 >> 24) & 0xFFL)]
^ T5[(int) ((nn1 >> 16) & 0xFFL)] ^ T6[(int) ((nn0 >> 8) & 0xFFL)]
^ T7[(int) (nn7 & 0xFFL)] ^ Kr6;
w7 = T0[(int) ((nn7 >> 56) & 0xFFL)] ^ T1[(int) ((nn6 >> 48) & 0xFFL)]
^ T2[(int) ((nn5 >> 40) & 0xFFL)]
^ T3[(int) ((nn4 >> 32) & 0xFFL)]
^ T4[(int) ((nn3 >> 24) & 0xFFL)]
^ T5[(int) ((nn2 >> 16) & 0xFFL)] ^ T6[(int) ((nn1 >> 8) & 0xFFL)]
^ T7[(int) (nn0 & 0xFFL)] ^ Kr7;
w0 = T0[(int)((nn0 >> 56) & 0xFFL)]
^ T1[(int)((nn7 >> 48) & 0xFFL)]
^ T2[(int)((nn6 >> 40) & 0xFFL)]
^ T3[(int)((nn5 >> 32) & 0xFFL)]
^ T4[(int)((nn4 >> 24) & 0xFFL)]
^ T5[(int)((nn3 >> 16) & 0xFFL)]
^ T6[(int)((nn2 >> 8) & 0xFFL)]
^ T7[(int)( nn1 & 0xFFL)] ^ Kr0;
w1 = T0[(int)((nn1 >> 56) & 0xFFL)]
^ T1[(int)((nn0 >> 48) & 0xFFL)]
^ T2[(int)((nn7 >> 40) & 0xFFL)]
^ T3[(int)((nn6 >> 32) & 0xFFL)]
^ T4[(int)((nn5 >> 24) & 0xFFL)]
^ T5[(int)((nn4 >> 16) & 0xFFL)]
^ T6[(int)((nn3 >> 8) & 0xFFL)]
^ T7[(int)( nn2 & 0xFFL)] ^ Kr1;
w2 = T0[(int)((nn2 >> 56) & 0xFFL)]
^ T1[(int)((nn1 >> 48) & 0xFFL)]
^ T2[(int)((nn0 >> 40) & 0xFFL)]
^ T3[(int)((nn7 >> 32) & 0xFFL)]
^ T4[(int)((nn6 >> 24) & 0xFFL)]
^ T5[(int)((nn5 >> 16) & 0xFFL)]
^ T6[(int)((nn4 >> 8) & 0xFFL)]
^ T7[(int)( nn3 & 0xFFL)] ^ Kr2;
w3 = T0[(int)((nn3 >> 56) & 0xFFL)]
^ T1[(int)((nn2 >> 48) & 0xFFL)]
^ T2[(int)((nn1 >> 40) & 0xFFL)]
^ T3[(int)((nn0 >> 32) & 0xFFL)]
^ T4[(int)((nn7 >> 24) & 0xFFL)]
^ T5[(int)((nn6 >> 16) & 0xFFL)]
^ T6[(int)((nn5 >> 8) & 0xFFL)]
^ T7[(int)( nn4 & 0xFFL)] ^ Kr3;
w4 = T0[(int)((nn4 >> 56) & 0xFFL)]
^ T1[(int)((nn3 >> 48) & 0xFFL)]
^ T2[(int)((nn2 >> 40) & 0xFFL)]
^ T3[(int)((nn1 >> 32) & 0xFFL)]
^ T4[(int)((nn0 >> 24) & 0xFFL)]
^ T5[(int)((nn7 >> 16) & 0xFFL)]
^ T6[(int)((nn6 >> 8) & 0xFFL)]
^ T7[(int)( nn5 & 0xFFL)] ^ Kr4;
w5 = T0[(int)((nn5 >> 56) & 0xFFL)]
^ T1[(int)((nn4 >> 48) & 0xFFL)]
^ T2[(int)((nn3 >> 40) & 0xFFL)]
^ T3[(int)((nn2 >> 32) & 0xFFL)]
^ T4[(int)((nn1 >> 24) & 0xFFL)]
^ T5[(int)((nn0 >> 16) & 0xFFL)]
^ T6[(int)((nn7 >> 8) & 0xFFL)]
^ T7[(int)( nn6 & 0xFFL)] ^ Kr5;
w6 = T0[(int)((nn6 >> 56) & 0xFFL)]
^ T1[(int)((nn5 >> 48) & 0xFFL)]
^ T2[(int)((nn4 >> 40) & 0xFFL)]
^ T3[(int)((nn3 >> 32) & 0xFFL)]
^ T4[(int)((nn2 >> 24) & 0xFFL)]
^ T5[(int)((nn1 >> 16) & 0xFFL)]
^ T6[(int)((nn0 >> 8) & 0xFFL)]
^ T7[(int)( nn7 & 0xFFL)] ^ Kr6;
w7 = T0[(int)((nn7 >> 56) & 0xFFL)]
^ T1[(int)((nn6 >> 48) & 0xFFL)]
^ T2[(int)((nn5 >> 40) & 0xFFL)]
^ T3[(int)((nn4 >> 32) & 0xFFL)]
^ T4[(int)((nn3 >> 24) & 0xFFL)]
^ T5[(int)((nn2 >> 16) & 0xFFL)]
^ T6[(int)((nn1 >> 8) & 0xFFL)]
^ T7[(int)( nn0 & 0xFFL)] ^ Kr7;
nn0 = w0;
nn1 = w1;
@ -547,7 +586,7 @@ public final class Whirlpool extends BaseHash
// are 33 (1 for the 1-bit followed by the 0-bits and the encoding of
// the count framed in a 256-bit block). our formula is then:
// count + 33 + padding = 0 (mod BLOCK_SIZE)
int n = (int) ((count + 33) % BLOCK_SIZE);
int n = (int)((count + 33) % BLOCK_SIZE);
int padding = n == 0 ? 33 : BLOCK_SIZE - n + 33;
byte[] result = new byte[padding];
@ -558,14 +597,14 @@ public final class Whirlpool extends BaseHash
// save (right justified) the number of bits hashed
long bits = count * 8;
int i = padding - 8;
result[i++] = (byte) (bits >>> 56);
result[i++] = (byte) (bits >>> 48);
result[i++] = (byte) (bits >>> 40);
result[i++] = (byte) (bits >>> 32);
result[i++] = (byte) (bits >>> 24);
result[i++] = (byte) (bits >>> 16);
result[i++] = (byte) (bits >>> 8);
result[i] = (byte) bits;
result[i++] = (byte)(bits >>> 56);
result[i++] = (byte)(bits >>> 48);
result[i++] = (byte)(bits >>> 40);
result[i++] = (byte)(bits >>> 32);
result[i++] = (byte)(bits >>> 24);
result[i++] = (byte)(bits >>> 16);
result[i++] = (byte)(bits >>> 8);
result[i ] = (byte) bits;
return result;
}
@ -573,38 +612,24 @@ public final class Whirlpool extends BaseHash
protected byte[] getResult()
{
// apply inverse mu to the context
byte[] result = new byte[] { (byte) (H0 >>> 56), (byte) (H0 >>> 48),
(byte) (H0 >>> 40), (byte) (H0 >>> 32),
(byte) (H0 >>> 24), (byte) (H0 >>> 16),
(byte) (H0 >>> 8), (byte) H0,
(byte) (H1 >>> 56), (byte) (H1 >>> 48),
(byte) (H1 >>> 40), (byte) (H1 >>> 32),
(byte) (H1 >>> 24), (byte) (H1 >>> 16),
(byte) (H1 >>> 8), (byte) H1,
(byte) (H2 >>> 56), (byte) (H2 >>> 48),
(byte) (H2 >>> 40), (byte) (H2 >>> 32),
(byte) (H2 >>> 24), (byte) (H2 >>> 16),
(byte) (H2 >>> 8), (byte) H2,
(byte) (H3 >>> 56), (byte) (H3 >>> 48),
(byte) (H3 >>> 40), (byte) (H3 >>> 32),
(byte) (H3 >>> 24), (byte) (H3 >>> 16),
(byte) (H3 >>> 8), (byte) H3,
(byte) (H4 >>> 56), (byte) (H4 >>> 48),
(byte) (H4 >>> 40), (byte) (H4 >>> 32),
(byte) (H4 >>> 24), (byte) (H4 >>> 16),
(byte) (H4 >>> 8), (byte) H4,
(byte) (H5 >>> 56), (byte) (H5 >>> 48),
(byte) (H5 >>> 40), (byte) (H5 >>> 32),
(byte) (H5 >>> 24), (byte) (H5 >>> 16),
(byte) (H5 >>> 8), (byte) H5,
(byte) (H6 >>> 56), (byte) (H6 >>> 48),
(byte) (H6 >>> 40), (byte) (H6 >>> 32),
(byte) (H6 >>> 24), (byte) (H6 >>> 16),
(byte) (H6 >>> 8), (byte) H6,
(byte) (H7 >>> 56), (byte) (H7 >>> 48),
(byte) (H7 >>> 40), (byte) (H7 >>> 32),
(byte) (H7 >>> 24), (byte) (H7 >>> 16),
(byte) (H7 >>> 8), (byte) H7 };
byte[] result = new byte[] {
(byte)(H0 >>> 56), (byte)(H0 >>> 48), (byte)(H0 >>> 40), (byte)(H0 >>> 32),
(byte)(H0 >>> 24), (byte)(H0 >>> 16), (byte)(H0 >>> 8), (byte) H0,
(byte)(H1 >>> 56), (byte)(H1 >>> 48), (byte)(H1 >>> 40), (byte)(H1 >>> 32),
(byte)(H1 >>> 24), (byte)(H1 >>> 16), (byte)(H1 >>> 8), (byte) H1,
(byte)(H2 >>> 56), (byte)(H2 >>> 48), (byte)(H2 >>> 40), (byte)(H2 >>> 32),
(byte)(H2 >>> 24), (byte)(H2 >>> 16), (byte)(H2 >>> 8), (byte) H2,
(byte)(H3 >>> 56), (byte)(H3 >>> 48), (byte)(H3 >>> 40), (byte)(H3 >>> 32),
(byte)(H3 >>> 24), (byte)(H3 >>> 16), (byte)(H3 >>> 8), (byte) H3,
(byte)(H4 >>> 56), (byte)(H4 >>> 48), (byte)(H4 >>> 40), (byte)(H4 >>> 32),
(byte)(H4 >>> 24), (byte)(H4 >>> 16), (byte)(H4 >>> 8), (byte) H4,
(byte)(H5 >>> 56), (byte)(H5 >>> 48), (byte)(H5 >>> 40), (byte)(H5 >>> 32),
(byte)(H5 >>> 24), (byte)(H5 >>> 16), (byte)(H5 >>> 8), (byte) H5,
(byte)(H6 >>> 56), (byte)(H6 >>> 48), (byte)(H6 >>> 40), (byte)(H6 >>> 32),
(byte)(H6 >>> 24), (byte)(H6 >>> 16), (byte)(H6 >>> 8), (byte) H6,
(byte)(H7 >>> 56), (byte)(H7 >>> 48), (byte)(H7 >>> 40), (byte)(H7 >>> 32),
(byte)(H7 >>> 24), (byte)(H7 >>> 16), (byte)(H7 >>> 8), (byte) H7
};
return result;
}
@ -617,10 +642,8 @@ public final class Whirlpool extends BaseHash
public boolean selfTest()
{
if (valid == null)
{
valid = new Boolean(
DIGEST0.equals(Util.toString(new Whirlpool().digest())));
}
valid = Boolean.valueOf(DIGEST0.equals(Util.toString(new Whirlpool().digest())));
return valid.booleanValue();
}
}

Some files were not shown because too many files have changed in this diff Show more