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