diff options
author | Matthias Klose <doko@gcc.gnu.org> | 2007-06-03 23:18:43 +0000 |
---|---|---|
committer | Matthias Klose <doko@gcc.gnu.org> | 2007-06-03 23:18:43 +0000 |
commit | e1bea0c0687c5f4551b3a6058ec37ce3705fa6cc (patch) | |
tree | a9c9e7d91c484d53fe154f9285fc57325572ce50 /libjava/classpath/gnu/java | |
parent | af333b9a7f9e1cc1029bec56d48f2de63acdf686 (diff) | |
download | gcc-e1bea0c0687c5f4551b3a6058ec37ce3705fa6cc.tar.gz |
libjava/classpath/ChangeLog.gcj:
2007-05-31 Matthias Klose <doko@ubuntu.com>
* javax/management/NotificationBroadcasterSupport.java
(getNotificationInfo): Add cast.
* native/jni/qt-peer/Makefile.am (AM_CXXFLAGS): Add libstdc++ include
directories.
* native/jni/qt-peer/Makefile.in: Regenerate.
libjava/ChangeLog:
2007-06-03 Matthias Klose <doko@ubuntu.com>
* java/io/natFileWin32.cc (setFilePermissions): New (stub only).
_access: Handle EXEC query, stub only.
2007-06-03 Matthias Klose <doko@ubuntu.com>
Merged from classpath:
* gnu/java/nio/SelectorProviderImpl.java: Whitespace merge.
* java/lang/System.java(inheritedChannel): New.
* java/lang/Character.java: Remove stray`;'.
* java/net/MulticastSocket.java: Merged.
* java/text/DateFormatSymbols.java(getInstance): New, comment updates.
* java/text/Collator.java(getInstance): Merged.
* java/util/Calendar.java: New attributes ALL_STYLES, SHORT, LONG.
getDisplayName, getDisplayNames: New.
* java/util/logging/Logger.java: Merged.
* Regenerate .class and .h files.
2007-06-03 Matthias Klose <doko@ubuntu.com>
* java/io/File.java: Merge with classpath-0.95, new method
setFilePermissions, new attribute EXEC.
* java/io/natFilePosix.cc (setFilePermissions): New.
_access: Handle EXEC query.
* classpath/lib/java/io/File.class, java/io/File.h: Regenerate.
2007-06-03 Matthias Klose <doko@ubuntu.com>
Imported GNU Classpath 0.95.
* classpath/Makefile.in,
classpath/native/jni/midi-dssi/Makefile.in,
classpath/native/jni/classpath/Makefile.in,
classpath/native/jni/Makefile.in,
classpath/native/jni/gconf-peer/Makefile.in,
classpath/native/jni/java-io/Makefile.in,
classpath/native/jni/native-lib/Makefile.in,
classpath/native/jni/java-util/Makefile.in,
classpath/native/jni/midi-alsa/Makefile.in,
classpath/native/jni/java-lang/Makefile.in,
classpath/native/jni/java-nio/Makefile.in,
classpath/native/jni/java-net/Makefile.in,
classpath/native/jni/xmlj/Makefile.in,
classpath/native/jni/qt-peer/Makefile.in,
classpath/native/jni/gtk-peer/Makefile.in,
classpath/native/Makefile.in, classpath/native/jawt/Makefile.in,
classpath/native/fdlibm/Makefile.in,
classpath/native/plugin/Makefile.in,
classpath/resource/Makefile.in, classpath/scripts/Makefile.in,
classpath/tools/Makefile.in, classpath/doc/Makefile.in,
classpath/doc/api/Makefile.in, classpath/lib/Makefile.in,
classpath/external/Makefile.in, classpath/external/jsr166/Makefile.in,
classpath/external/sax/Makefile.in,
classpath/external/w3c_dom/Makefile.in,
classpath/external/relaxngDatatype/Makefile.in,
classpath/include/Makefile.in,
classpath/examples/Makefile.in: Regenerate.
* classpath/config.guess, classpath/config.sub,
classpath/ltmain.sh : Update.
* classpath/configure, classpath/depcomp, classpath/missing,
classpath/aclocal.m4, classpath/install-sh: Regenerate.
* gnu/classpath/Configuration.java (CLASSPATH_VERSION): Now 0.95.
* sources.am: Regenerate.
* Makefile.in: Regenerate.
* Update the .class files and generated CNI header files, add new
.class and generated CNI header files.
* Remove generated files for removed java source files:
classpath/gnu/java/net/BASE64.java,
classpath/gnu/java/security/util/Base64.java,
classpath/gnu/java/awt/peer/gtk/GThreadMutex.java,
classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java,
classpath/gnu/java/awt/font/autofit/Scaler.java,
classpath/gnu/classpath/jdwp/util/Value.java,
classpath/gnu/javax/net/ssl/Base64.java.
* Remove empty directories.
* Makefile.am(nat_source_files): Add natVMOperatingSystemMXBeanImpl.cc.
* java/lang/Class.java(setAccessible): Merge from classpath.
* java/util/Locale.java: Remove.
* gnu/java/lang/management/VMOperatingSystemMXBeanImpl.java,
gnu/java/lang/management/natVMOperatingSystemMXBeanImpl.cc: New.
* gcj/javaprims.h: Update class declarations.
* scripts/classes.pl: Update usage.
* HACKING: Mention to build all peers.
From-SVN: r125302
Diffstat (limited to 'libjava/classpath/gnu/java')
127 files changed, 8058 insertions, 3601 deletions
diff --git a/libjava/classpath/gnu/java/awt/AWTUtilities.java b/libjava/classpath/gnu/java/awt/AWTUtilities.java index ca7b5511853..1b68703697f 100644 --- a/libjava/classpath/gnu/java/awt/AWTUtilities.java +++ b/libjava/classpath/gnu/java/awt/AWTUtilities.java @@ -1,5 +1,5 @@ /* AWTUtilities.java -- Common utility methods for AWT and Swing. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -47,6 +47,7 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; +import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.AbstractSequentialList; import java.util.List; @@ -694,4 +695,204 @@ public class AWTUtilities { return java.awt.EventQueue.isDispatchThread(); } + + /** + * Returns whether the specified key code is valid. + */ + public static boolean isValidKey(int keyCode) + { + switch (keyCode) + { + case KeyEvent.VK_ENTER: + case KeyEvent.VK_BACK_SPACE: + case KeyEvent.VK_TAB: + case KeyEvent.VK_CANCEL: + case KeyEvent.VK_CLEAR: + case KeyEvent.VK_SHIFT: + case KeyEvent.VK_CONTROL: + case KeyEvent.VK_ALT: + case KeyEvent.VK_PAUSE: + case KeyEvent.VK_CAPS_LOCK: + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + case KeyEvent.VK_PAGE_UP: + case KeyEvent.VK_PAGE_DOWN: + case KeyEvent.VK_END: + case KeyEvent.VK_HOME: + case KeyEvent.VK_LEFT: + case KeyEvent.VK_UP: + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_DOWN: + case KeyEvent.VK_COMMA: + case KeyEvent.VK_MINUS: + case KeyEvent.VK_PERIOD: + case KeyEvent.VK_SLASH: + case KeyEvent.VK_0: + case KeyEvent.VK_1: + case KeyEvent.VK_2: + case KeyEvent.VK_3: + case KeyEvent.VK_4: + case KeyEvent.VK_5: + case KeyEvent.VK_6: + case KeyEvent.VK_7: + case KeyEvent.VK_8: + case KeyEvent.VK_9: + case KeyEvent.VK_SEMICOLON: + case KeyEvent.VK_EQUALS: + case KeyEvent.VK_A: + case KeyEvent.VK_B: + case KeyEvent.VK_C: + case KeyEvent.VK_D: + case KeyEvent.VK_E: + case KeyEvent.VK_F: + case KeyEvent.VK_G: + case KeyEvent.VK_H: + case KeyEvent.VK_I: + case KeyEvent.VK_J: + case KeyEvent.VK_K: + case KeyEvent.VK_L: + case KeyEvent.VK_M: + case KeyEvent.VK_N: + case KeyEvent.VK_O: + case KeyEvent.VK_P: + case KeyEvent.VK_Q: + case KeyEvent.VK_R: + case KeyEvent.VK_S: + case KeyEvent.VK_T: + case KeyEvent.VK_U: + case KeyEvent.VK_V: + case KeyEvent.VK_W: + case KeyEvent.VK_X: + case KeyEvent.VK_Y: + case KeyEvent.VK_Z: + case KeyEvent.VK_OPEN_BRACKET: + case KeyEvent.VK_BACK_SLASH: + case KeyEvent.VK_CLOSE_BRACKET: + case KeyEvent.VK_NUMPAD0: + case KeyEvent.VK_NUMPAD1: + case KeyEvent.VK_NUMPAD2: + case KeyEvent.VK_NUMPAD3: + case KeyEvent.VK_NUMPAD4: + case KeyEvent.VK_NUMPAD5: + case KeyEvent.VK_NUMPAD6: + case KeyEvent.VK_NUMPAD7: + case KeyEvent.VK_NUMPAD8: + case KeyEvent.VK_NUMPAD9: + case KeyEvent.VK_MULTIPLY: + case KeyEvent.VK_ADD: + case KeyEvent.VK_SEPARATOR: + case KeyEvent.VK_SUBTRACT: + case KeyEvent.VK_DECIMAL: + case KeyEvent.VK_DIVIDE: + case KeyEvent.VK_DELETE: + case KeyEvent.VK_NUM_LOCK: + case KeyEvent.VK_SCROLL_LOCK: + case KeyEvent.VK_F1: + case KeyEvent.VK_F2: + case KeyEvent.VK_F3: + case KeyEvent.VK_F4: + case KeyEvent.VK_F5: + case KeyEvent.VK_F6: + case KeyEvent.VK_F7: + case KeyEvent.VK_F8: + case KeyEvent.VK_F9: + case KeyEvent.VK_F10: + case KeyEvent.VK_F11: + case KeyEvent.VK_F12: + case KeyEvent.VK_F13: + case KeyEvent.VK_F14: + case KeyEvent.VK_F15: + case KeyEvent.VK_F16: + case KeyEvent.VK_F17: + case KeyEvent.VK_F18: + case KeyEvent.VK_F19: + case KeyEvent.VK_F20: + case KeyEvent.VK_F21: + case KeyEvent.VK_F22: + case KeyEvent.VK_F23: + case KeyEvent.VK_F24: + case KeyEvent.VK_PRINTSCREEN: + case KeyEvent.VK_INSERT: + case KeyEvent.VK_HELP: + case KeyEvent.VK_META: + case KeyEvent.VK_BACK_QUOTE: + case KeyEvent.VK_QUOTE: + case KeyEvent.VK_KP_UP: + case KeyEvent.VK_KP_DOWN: + case KeyEvent.VK_KP_LEFT: + case KeyEvent.VK_KP_RIGHT: + case KeyEvent.VK_DEAD_GRAVE: + case KeyEvent.VK_DEAD_ACUTE: + case KeyEvent.VK_DEAD_CIRCUMFLEX: + case KeyEvent.VK_DEAD_TILDE: + case KeyEvent.VK_DEAD_MACRON: + case KeyEvent.VK_DEAD_BREVE: + case KeyEvent.VK_DEAD_ABOVEDOT: + case KeyEvent.VK_DEAD_DIAERESIS: + case KeyEvent.VK_DEAD_ABOVERING: + case KeyEvent.VK_DEAD_DOUBLEACUTE: + case KeyEvent.VK_DEAD_CARON: + case KeyEvent.VK_DEAD_CEDILLA: + case KeyEvent.VK_DEAD_OGONEK: + case KeyEvent.VK_DEAD_IOTA: + case KeyEvent.VK_DEAD_VOICED_SOUND: + case KeyEvent.VK_DEAD_SEMIVOICED_SOUND: + case KeyEvent.VK_AMPERSAND: + case KeyEvent.VK_ASTERISK: + case KeyEvent.VK_QUOTEDBL: + case KeyEvent.VK_LESS: + case KeyEvent.VK_GREATER: + case KeyEvent.VK_BRACELEFT: + case KeyEvent.VK_BRACERIGHT: + case KeyEvent.VK_AT: + case KeyEvent.VK_COLON: + case KeyEvent.VK_CIRCUMFLEX: + case KeyEvent.VK_DOLLAR: + case KeyEvent.VK_EURO_SIGN: + case KeyEvent.VK_EXCLAMATION_MARK: + case KeyEvent.VK_INVERTED_EXCLAMATION_MARK: + case KeyEvent.VK_LEFT_PARENTHESIS: + case KeyEvent.VK_NUMBER_SIGN: + case KeyEvent.VK_PLUS: + case KeyEvent.VK_RIGHT_PARENTHESIS: + case KeyEvent.VK_UNDERSCORE: + case KeyEvent.VK_FINAL: + case KeyEvent.VK_CONVERT: + case KeyEvent.VK_NONCONVERT: + case KeyEvent.VK_ACCEPT: + case KeyEvent.VK_MODECHANGE: + case KeyEvent.VK_KANA: + case KeyEvent.VK_KANJI: + case KeyEvent.VK_ALPHANUMERIC: + case KeyEvent.VK_KATAKANA: + case KeyEvent.VK_HIRAGANA: + case KeyEvent.VK_FULL_WIDTH: + case KeyEvent.VK_HALF_WIDTH: + case KeyEvent.VK_ROMAN_CHARACTERS: + case KeyEvent.VK_ALL_CANDIDATES: + case KeyEvent.VK_PREVIOUS_CANDIDATE: + case KeyEvent.VK_CODE_INPUT: + case KeyEvent.VK_JAPANESE_KATAKANA: + case KeyEvent.VK_JAPANESE_HIRAGANA: + case KeyEvent.VK_JAPANESE_ROMAN: + case KeyEvent.VK_KANA_LOCK: + case KeyEvent.VK_INPUT_METHOD_ON_OFF: + case KeyEvent.VK_CUT: + case KeyEvent.VK_COPY: + case KeyEvent.VK_PASTE: + case KeyEvent.VK_UNDO: + case KeyEvent.VK_AGAIN: + case KeyEvent.VK_FIND: + case KeyEvent.VK_PROPS: + case KeyEvent.VK_STOP: + case KeyEvent.VK_COMPOSE: + case KeyEvent.VK_ALT_GRAPH: + case KeyEvent.VK_BEGIN: + case KeyEvent.VK_CONTEXT_MENU: + case KeyEvent.VK_WINDOWS: + return true; + default: + return false; + } + } } diff --git a/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java new file mode 100644 index 00000000000..865da1d9594 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java @@ -0,0 +1,67 @@ +/* ClasspathGraphicsEnvironment.java + Copyright (C) 2007 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; + +import java.awt.GraphicsEnvironment; +import java.awt.image.ColorModel; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; + +/** + * This class extends the GraphicsEnvironment API with some Classpath-specific + * methods, in order to provide optimized graphics handling. + * + * @author Francis Kung <fkung@redhat.com> + */ +public abstract class ClasspathGraphicsEnvironment + extends GraphicsEnvironment +{ + /** + * Returns an appropriate Raster that can efficiently back a + * BufferedImage with the given ColorModel and SampleModel. + * + * @param cm The color model. + * @param sm The samepl model. + * @return An appropriate WritableRaster, or null if acceleration/optimization + * is not available for the given colour model / sample model. + */ + public WritableRaster createRaster(ColorModel cm, SampleModel sm) + { + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/ClasspathToolkit.java b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java index 968cc3b1643..d78fbab4e1e 100644 --- a/libjava/classpath/gnu/java/awt/ClasspathToolkit.java +++ b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java @@ -38,36 +38,28 @@ exception statement from your version. */ package gnu.java.awt; -import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathDesktopPeer; import gnu.java.awt.peer.ClasspathFontPeer; import gnu.java.awt.peer.EmbeddedWindowPeer; import gnu.java.security.action.SetAccessibleAction; import java.awt.AWTException; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.DisplayMode; +import java.awt.Desktop; import java.awt.Font; -import java.awt.FontMetrics; +import java.awt.FontFormatException; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; -import java.awt.Image; -import java.awt.Point; +import java.awt.HeadlessException; import java.awt.Toolkit; -import java.awt.font.FontRenderContext; -import java.awt.image.ColorModel; -import java.awt.image.ImageProducer; +import java.awt.font.TextAttribute; +import java.awt.peer.DesktopPeer; import java.awt.peer.RobotPeer; -import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.text.AttributedString; -import java.util.HashMap; -import java.util.Map; import java.security.AccessController; +import java.util.Map; import javax.imageio.spi.IIORegistry; @@ -118,7 +110,8 @@ public abstract class ClasspathToolkit * this font peer should have, such as size, weight, family name, or * transformation. */ - public abstract ClasspathFontPeer getClasspathFontPeer (String name, Map attrs); + public abstract ClasspathFontPeer getClasspathFontPeer (String name, + Map<?,?> attrs); /** * Creates a {@link Font}, in a platform-specific manner. @@ -137,9 +130,8 @@ public abstract class ClasspathToolkit try { Constructor fontConstructor = Font.class.getDeclaredConstructor - (new Class[] { String.class, Map.class }); - AccessController.doPrivileged - (new SetAccessibleAction(fontConstructor)); + (new Class[] { String.class, Map.class }); + AccessController.doPrivileged(new SetAccessibleAction(fontConstructor)); f = (Font) fontConstructor.newInstance(new Object[] { name, attrs }); } catch (IllegalAccessException e) @@ -224,5 +216,18 @@ public abstract class ClasspathToolkit { return -1; } + + /* (non-Javadoc) + * @see java.awt.Toolkit#createDesktopPeer(java.awt.Desktop) + */ + protected DesktopPeer createDesktopPeer(Desktop target) + throws HeadlessException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + return ClasspathDesktopPeer.getDesktop(); + } + } diff --git a/libjava/classpath/gnu/java/awt/font/FontDelegate.java b/libjava/classpath/gnu/java/awt/font/FontDelegate.java index a26510ee2de..030f9d3bca5 100644 --- a/libjava/classpath/gnu/java/awt/font/FontDelegate.java +++ b/libjava/classpath/gnu/java/awt/font/FontDelegate.java @@ -61,6 +61,13 @@ import java.util.Locale; */ public interface FontDelegate { + public static final int FLAG_FITTED = 1 << 0; + public static final int FLAG_NO_HINT_HORIZONTAL = 1 << 1; + public static final int FLAG_NO_HINT_VERTICAL = 1 << 2; + public static final int FLAG_NO_HINT_EDGE_POINTS = 1 << 3; + public static final int FLAG_NO_HINT_STRONG_POINTS = 1 << 4; + public static final int FLAG_NO_HINT_WEAK_POINTS = 1 << 5; + /** * Returns the full name of this font face in the specified * locale, for example <i>“Univers Light”</i>. @@ -221,7 +228,8 @@ public interface FontDelegate float pointSize, AffineTransform transform, boolean antialias, - boolean fractionalMetrics); + boolean fractionalMetrics, + int type); /** diff --git a/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java b/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java index f17a4511375..2f73dce77b0 100644 --- a/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java +++ b/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java @@ -164,7 +164,9 @@ public class GNUGlyphVector renderContext.usesFractionalMetrics(), /* horizontal */ true, advance); - pos[p] = x += advance.x; + // FIXME: We shouldn't round here, but instead hint the metrics + // correctly. + pos[p] = x += Math.round(advance.x); pos[p + 1] = y += advance.y; } valid = true; @@ -284,6 +286,22 @@ public class GNUGlyphVector return outline; } + public Shape getOutline(float x, float y, int type) + { + validate(); + + GeneralPath outline = new GeneralPath(); + int len = glyphs.length; + for (int i = 0; i < len; i++) + { + GeneralPath p = new GeneralPath(getGlyphOutline(i, type)); + outline.append(p, false); + } + AffineTransform t = new AffineTransform(); + t.translate(x, y); + outline.transform(t); + return outline; + } /** * Determines the shape of the specified glyph. @@ -309,7 +327,8 @@ public class GNUGlyphVector path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx, renderContext.isAntiAliased(), - renderContext.usesFractionalMetrics()); + renderContext.usesFractionalMetrics(), + FontDelegate.FLAG_FITTED); tx = new AffineTransform(); tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]); @@ -317,6 +336,32 @@ public class GNUGlyphVector return path; } + public Shape getGlyphOutline(int glyphIndex, int type) + { + 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(), + type); + + 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 diff --git a/libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java b/libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java new file mode 100644 index 00000000000..b0420ab7a2d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java @@ -0,0 +1,83 @@ +/* AutoHinter.java -- The entry point into the hinter implementation. + 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.autofit; + +import gnu.java.awt.font.opentype.Hinter; +import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Fixed; +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * The public interface to the automatic gridfitter. + */ +public class AutoHinter + implements Hinter +{ + Latin latinScript; + LatinMetrics metrics; + GlyphHints hints; + + HintScaler scaler = new HintScaler(); + public void init(OpenTypeFont font) + { + // TODO: Should support other scripts too. + latinScript = new Latin(); + metrics = new LatinMetrics(font); + latinScript.initMetrics(metrics, font); + scaler.face = font; + } + + public void applyHints(Zone outline) + { + if (hints == null) + hints = new GlyphHints(); + scaler.xScale = Fixed.valueOf16(outline.scaleX * 64); + scaler.yScale = Fixed.valueOf16(outline.scaleY * 64); + latinScript.scaleMetrics(metrics, scaler); + latinScript.applyHints(hints, outline, metrics); + } + + public void setFlags(int flags) + { + if (hints == null) + hints = new GlyphHints(); + hints.flags = flags; + } + +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java b/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java index b2c9912342b..87f2abcc3df 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java @@ -1,4 +1,4 @@ -/* AxisHints.java -- FIXME: briefly describe file purpose +/* AxisHints.java -- Hints specific to an axis Copyright (C) 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,4 +42,71 @@ class AxisHints { Segment[] segments; + int majorDir; + int numSegments; + int numEdges; + Edge[] edges; + + AxisHints() + { + segments = new Segment[4]; + edges = new Edge[4]; + } + + Segment newSegment() + { + if (numSegments >= segments.length) + { + // Grow array. + int newMax = segments.length; + newMax += (newMax >> 2) + 4; // From FreeType. + Segment[] newSegs = new Segment[newMax]; + System.arraycopy(segments, 0, newSegs, 0, numSegments); + segments = newSegs; + } + Segment seg = new Segment(); + segments[numSegments] = seg; + numSegments++; + return seg; + } + + public Edge newEdge(int pos) + { + if (numEdges >= edges.length) + { + // Grow array. + int newMax = edges.length; + newMax += (newMax >> 2) + 4; // From FreeType. + Edge[] newEdges = new Edge[newMax]; + System.arraycopy(edges, 0, newEdges, 0, numEdges); + edges = newEdges; + } + int edgeIndex = numEdges; + Edge edge = edges[edgeIndex] = new Edge(); + while (edgeIndex > 0 && edges[edgeIndex - 1].fpos > pos) + { + edges[edgeIndex] = edges[edgeIndex - 1]; + edgeIndex--; + } + edges[edgeIndex] = edge; + numEdges++; + edge.fpos = pos; + + return edge; + + } + + int getEdgeIndex(Edge edge2) + { + int idx = -1; + for (int i = 0; i < numEdges; i++) + { + if (edges[i] == edge2) + { + idx = i; + break; + } + } + return idx; + } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Constants.java b/libjava/classpath/gnu/java/awt/font/autofit/Constants.java index cb3992825ab..c5b90fa5485 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/Constants.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/Constants.java @@ -58,4 +58,29 @@ interface Constants * The number of dimensions. */ static final int DIMENSION_MAX = 2; + + /** + * Indicates a vector with no specific direction. + */ + static final int DIR_NONE = 0; + + /** + * Right direction. + */ + static final int DIR_RIGHT = 1; + + /** + * Left direction. + */ + static final int DIR_LEFT = -1; + + /** + * Up direction. + */ + static final int DIR_UP = 2; + + /** + * Down direction. + */ + static final int DIR_DOWN = -2; } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Edge.java b/libjava/classpath/gnu/java/awt/font/autofit/Edge.java new file mode 100644 index 00000000000..d9736650b5f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Edge.java @@ -0,0 +1,80 @@ +/* Edge.java -- An edge of segments + 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.autofit; + +class Edge +{ + int fpos; + Segment first; + Segment last; + int opos; + Edge link; + Edge serif; + int flags; + int dir; + Width blueEdge; + int pos; + int scale; + + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[Edge] id"); + s.append(hashCode()); + s.append(", fpos: "); + s.append(fpos); + s.append(", opos: "); + s.append(opos); + s.append(", pos: "); + s.append(pos); + s.append(", dir: "); + s.append(dir); + s.append(", serif: "); + s.append(serif != null ? serif.hashCode() : "null"); + s.append(", link: "); + s.append(link != null ? link.hashCode() : "null"); + s.append(", flags: " + flags); + s.append(", blue: " + blueEdge); + s.append(", first: "); + s.append(first == null ? "null" : first.hashCode()); + s.append(", last: "); + s.append(last == null ? "null" : last.hashCode()); + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java b/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java index ad73a04a69b..72f07ed81fc 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java @@ -38,12 +38,16 @@ exception statement from your version. */ package gnu.java.awt.font.autofit; +import gnu.java.awt.font.FontDelegate; +import gnu.java.awt.font.opentype.truetype.Fixed; +import gnu.java.awt.font.opentype.truetype.Point; import gnu.java.awt.font.opentype.truetype.Zone; /** * The data and methods used for the actual hinting process. */ class GlyphHints + implements Constants { int xScale; @@ -53,23 +57,584 @@ class GlyphHints AxisHints[] axis; - void rescale(ScriptMetrics metrics) + Point[] points; + int numPoints; + int maxPoints; + + Point[] contours; + int numContours; + int maxContours; + + ScriptMetrics metrics; + + int flags; + + GlyphHints() + { + axis = new AxisHints[Constants.DIMENSION_MAX]; + axis[Constants.DIMENSION_VERT] = new AxisHints(); + axis[Constants.DIMENSION_HORZ] = new AxisHints(); + + xScale = Fixed.ONE; + yScale = Fixed.ONE; + } + + void rescale(ScriptMetrics m) { - // TODO: Implement. + metrics = m; + // TODO: Copy scalerFlags. } void reload(Zone outline) { - // TODO: Implement. + numPoints = 0; + numContours = 0; + axis[0].numSegments = 0; + axis[0].numEdges = 0; + axis[1].numSegments = 0; + axis[1].numEdges = 0; + + // Create/reallocate the contours array. + int newMax = outline.getNumContours(); + if (newMax > maxContours || contours == null) + { + newMax = (newMax + 3) & ~3; // Taken from afhints.c . + Point[] newContours = new Point[newMax]; + if (contours != null) + { + System.arraycopy(contours, 0, newContours, 0, maxContours); + } + contours = newContours; + maxContours = newMax; + } + + // Create/reallocate the points array. + newMax = outline.getSize() + 2; + if (newMax > maxPoints || points == null) + { + newMax = (newMax + 2 + 7) & ~7; // Taken from afhints.c . + Point[] newPoints = new Point[newMax]; + if (points != null) + { + System.arraycopy(points, 0, newPoints, 0, maxPoints); + } + points = newPoints; + maxPoints = newMax; + } + + numPoints = outline.getSize() - 4; // 4 phantom points. + numContours = outline.getNumContours(); + + // Set major direction. We don't handle Type 1 fonts yet. + axis[DIMENSION_HORZ].majorDir = DIR_UP; + axis[DIMENSION_VERT].majorDir = DIR_LEFT; + + // TODO: Freetype seems to scale and translate the glyph at that point. + // I suppose that this is not really needed. + // The scales are scaling from font units to 1/64 device pixels. + xScale = Fixed.valueOf16(outline.scaleX * 64); + yScale = Fixed.valueOf16(outline.scaleY * 64); + + // FIXME: What is that xDelta and yDelta used for? + System.arraycopy(outline.getPoints(), 0, points, 0, numPoints); + + // Setup prev and next and contours array. + // TODO: Probably cache this. + contours = new Point[numContours]; + Point currentContour = points[0]; + for (int i = 0, cIndex = 0; i < numPoints; i++) + { + // Start new contour when the last point has been a contour end. + if (outline.isContourEnd(i)) + { + // Connect the contour end point to the start point. + points[i].setNext(currentContour); + currentContour.setPrev(points[i]); + contours[cIndex] = currentContour; + cIndex++; + currentContour = i < numPoints - 1 ? points[i + 1] : null; + } + else + { + // Connect the current and the previous point. + points[i].setNext(points[i + 1]); + points[i + 1].setPrev(points[i]); + } + } + // Compute directions of in and out vectors of all points as well + // as the weak point flag. + for (int i = 0; i < numPoints; i++) + { + // Compute in and out dir. + Point p = points[i]; + Point prev = p.getPrev(); + int inX = p.getOrigX() - prev.getOrigX(); + int inY = p.getOrigY() - prev.getOrigY(); + p.setInDir(Utils.computeDirection(inX, inY)); + Point next = p.getNext(); + int outX = next.getOrigX() - p.getOrigX(); + int outY = next.getOrigY() - p.getOrigY(); + p.setOutDir(Utils.computeDirection(outX, outY)); + + if (p.isControlPoint()) + { + setWeakPoint(p); + } + else if (p.getOutDir() == p.getInDir()) + { + if (p.getOutDir() != DIR_NONE) + setWeakPoint(p); + else + { + int angleIn = Utils.atan(inY, inX); + int angleOut = Utils.atan(outY, outX); + int delta = Utils.angleDiff(angleIn, angleOut); + if (delta < 2 && delta > -2) + setWeakPoint(p); + } + } + else if (p.getInDir() == - p.getOutDir()) + { + setWeakPoint(p); + } + } + computeInflectionPoints(); + } + + private void setWeakPoint(Point p) + { + p.setFlags((byte) (p.getFlags() | Point.FLAG_WEAK_INTERPOLATION)); + } + + /** + * Computes the inflection points for a glyph. + */ + private void computeInflectionPoints() + { + // Do each contour separately. + contours : for (int c = 0; c < contours.length; c++) + { + Point point = contours[c]; + Point first = point; + Point start = point; + Point end = point; + do + { + end = end.getNext(); + if (end == first) + continue contours; + } while (end.getOrigX() == first.getOrigX() + && end.getOrigY() == first.getOrigY()); + + // Extend segment start whenever possible. + Point before = start; + int angleIn; + int angleSeg = Utils.atan(end.getOrigX() - start.getOrigX(), + end.getOrigY() - start.getOrigY()); + do + { + do + { + start = before; + before = before.getPrev(); + if (before == first) + continue contours; + } while (before.getOrigX() == start.getOrigX() + && before.getOrigY() == start.getOrigY()); + angleIn = Utils.atan(start.getOrigX() - before.getOrigX(), + start.getOrigY() - before.getOrigY()); + } while (angleIn == angleSeg); + + first = start; + int diffIn = Utils.angleDiff(angleIn, angleSeg); + // Now, process all segments in the contour. + Point after; + boolean finished = false; + int angleOut, diffOut; + do + { + // First, extend the current segment's end whenever possible. + after = end; + do + { + do + { + end = after; + after = after.getNext(); + if (after == first) + finished = true; + } while (end.getOrigX() == after.getOrigX() + && end.getOrigY() == after.getOrigY()); + angleOut = Utils.atan(after.getOrigX() - end.getOrigX(), + after.getOrigY() - end.getOrigY()); + } while (angleOut == angleSeg); + diffOut = Utils.angleDiff(angleSeg, angleOut); + if ((diffIn ^ diffOut) < 0) + { + // diffIn and diffOut have different signs, we have + // inflection points here. + do + { + start.addFlags(Point.FLAG_INFLECTION); + start = start.getNext(); + } while (start != end); + start.addFlags(Point.FLAG_INFLECTION); + } + start = end; + end = after; + angleSeg = angleOut; + diffIn = diffOut; + } while (! finished); + } + } + + boolean doHorizontal() + { + return (flags & FontDelegate.FLAG_NO_HINT_HORIZONTAL) == 0; + } + + boolean doVertical() + { + return (flags & FontDelegate.FLAG_NO_HINT_VERTICAL) == 0; + } + + void alignWeakPoints(int dim) + { + short touchFlag; + Point point; + // PASS 1 : Move segments to edge positions. + if (dim == DIMENSION_HORZ) + { + touchFlag = Point.FLAG_DONE_X; + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setU(point.getX()); + point.setV(point.getScaledX()); + } + } + else + { + touchFlag = Point.FLAG_DONE_Y; + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setU(point.getY()); + point.setV(point.getScaledY()); + } + } + point = points[0]; + for (int c = 0; c < numContours; c++) + { + point = contours[c]; + int idx = getPointIndex(point); + Point endPoint = point.getPrev(); + int endIdx = getPointIndex(endPoint); + int firstIdx = idx; + while (idx <= endIdx + && (point.getFlags() & touchFlag) == 0) + { + idx++; + point = points[idx]; + } + if (idx <= endIdx) + { + int firstTouched = idx; + int curTouched = idx; + idx++; + point = points[idx]; + while (idx <= endIdx) + { + if ((point.getFlags() & touchFlag) != 0) + { + // We found two successive touch points. We interpolate + // all contour points between them. + iupInterp(curTouched + 1, idx - 1, curTouched, idx); + curTouched = idx; + } + idx++; + point = points[idx]; + } + if (curTouched == firstTouched) + { + // This is a special case: Only one point was touched in the + // contour. We thus simply shift the whole contour. + iupShift(firstIdx, endIdx, curTouched); + } + else + { + // Now interpolate after the last touched point to the end + // of the contour. + iupInterp(curTouched + 1, endIdx, curTouched, firstTouched); + // If the first contour point isn't touched, interpolate + // from the contour start to the first touched point. + if (firstTouched > 0) + { + iupInterp(firstIdx, firstTouched - 1, curTouched, + firstTouched); + } + } + } + } + // Now store the values back. + if (dim == DIMENSION_HORZ) + { + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setX(point.getU()); + } + } + else + { + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setY(point.getU()); + } + } + } + + private void iupShift(int p1, int p2, int ref) + { + int delta = points[ref].getU() - points[ref].getV(); + for (int p = p1; p < ref; p++) + { + points[p].setU(points[p].getV() + delta); + } + for (int p = ref + 1; p <= p2; p++) + { + points[p].setU(points[p].getV() + delta); + } + } + + private void iupInterp(int p1, int p2, int ref1, int ref2) + { + int v1 = points[ref1].getV(); + int v2 = points[ref2].getV(); + int d1 = points[ref1].getU() - v1; + int d2 = points[ref2].getU() - v2; + if (p1 > p2) + return; + if (v1 == v2) + { + for (int p = p1; p <= p2; p++) + { + int u = points[p].getV(); + if (u <= v1) + u += d1; + else + u += d2; + points[p].setU(u); + } + } + else if (v1 < v2) + { + for (int p = p1; p <= p2; p++) + { + int u = points[p].getV(); + if (u <= v1) + u += d1; + else if (u >= v2) + u += d2; + else + { + u = points[ref1].getU() + Utils.mulDiv(u - v1, + points[ref2].getU() + - points[ref1].getU(), + v2 - v1); + } + points[p].setU(u); + } + } + else + { + for (int p = p1; p <= p2; p++) + { + int u = points[p].getV(); + if (u <= v2) + u += d2; + else if (u >= v1) + u += d1; + else + { + u = points[ref1].getU() + Utils.mulDiv(u - v1, + points[ref2].getU() + - points[ref1].getU(), + v2 - v1); + } + points[p].setU(u); + } + } + } + + void alignStrongPoints(int dim) + { + AxisHints ax = axis[dim]; + Edge[] edges = ax.edges; + int numEdges = ax.numEdges; + short touchFlag; + if (dim == DIMENSION_HORZ) + touchFlag = Point.FLAG_DONE_X; + else + touchFlag = Point.FLAG_DONE_Y; + + if (numEdges > 0) + { + for (int p = 0; p < numPoints; p++) + { + Point point = points[p]; + if ((point.getFlags() & touchFlag) != 0) + continue; + // If this point is a candidate for weak interpolation, we + // interpolate it after all strong points have been processed. + if ((point.getFlags() & Point.FLAG_WEAK_INTERPOLATION) != 0 + && (point.getFlags() & Point.FLAG_INFLECTION) == 0) + continue; + + int u, ou, fu, delta; + if (dim == DIMENSION_VERT) + { + u = point.getOrigY(); + ou = point.getScaledY(); + } + else + { + u = point.getOrigX(); + ou = point.getScaledX(); + } + fu = u; + // Is the point before the first edge? + Edge edge = edges[0]; + // Inversed vertical dimension. + delta = edge.fpos - u; + if (delta >= 0) + { + u = edge.pos - (edge.opos - ou); + storePoint(point, u, dim, touchFlag); + } + else + { + // Is the point after the last edge? + edge = edges[numEdges - 1]; + delta = u - edge.fpos; + if (delta >= 0) + { + u = edge.pos + (ou - edge.opos); + storePoint(point, u, dim, touchFlag); + } + else + { + // Find enclosing edges. + int min = 0; + int max = numEdges; + int mid, fpos; + boolean found = false; + while (min < max) + { + mid = (max + min) / 2; + edge = edges[mid]; + fpos = edge.fpos; + if (u < fpos) + max = mid; + else if (u > fpos) + min = mid + 1; + else + { + // Directly on the edge. + u = edge.pos; + storePoint(point, u, dim, touchFlag); + found = true; + break; + } + } + if (! found) + { + Edge before = edges[min - 1]; + Edge after = edges[min]; + if (before.scale == 0) + { + before.scale = Fixed.div16(after.pos - before.pos, + after.fpos - before.fpos); + } + u = before.pos + Fixed.mul16(fu - before.fpos, + before.scale); + } + storePoint(point, u, dim, touchFlag); + } + } + } + } + } + + private void storePoint(Point p, int u, int dim, short touchFlag) + { + if (dim == DIMENSION_HORZ) + p.setX(u); + else + p.setY(u); + p.addFlags(touchFlag); + } + + void alignEdgePoints(int dim) + { + AxisHints ax = axis[dim]; + Edge[] edges = ax.edges; + int numEdges = ax.numEdges; + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + Segment seg = edge.first; + do + { + Point point = seg.first; + while (true) + { + if (dim == DIMENSION_HORZ) + { + point.setX(edge.pos); + point.addFlags(Point.FLAG_DONE_X); + } + else + { + point.setY(edge.pos); + point.addFlags(Point.FLAG_DONE_Y); + } + if (point == seg.last) + break; + point = point.getNext(); + } + seg = seg.edgeNext; + } while (seg != edge.first); + } + } + + private int getPointIndex(Point p) + { + int idx = -1; + for (int i = 0; i < numPoints; i++) + { + if (p == points[i]) + { + idx = i; + break; + } + } + return idx; + } + + public boolean doAlignEdgePoints() + { + return (flags & FontDelegate.FLAG_NO_HINT_EDGE_POINTS) == 0; } - void computeSegments(int dim) + public boolean doAlignStrongPoints() { - // TODO: Implement. + return (flags & FontDelegate.FLAG_NO_HINT_STRONG_POINTS) == 0; } - void linkSegments(int dim) + public boolean doAlignWeakPoints() { - // TODO: Implement. + return (flags & FontDelegate.FLAG_NO_HINT_WEAK_POINTS) == 0; } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Scaler.java b/libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java index 10518512578..01276b4db01 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/Scaler.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java @@ -40,7 +40,7 @@ package gnu.java.awt.font.autofit; import gnu.java.awt.font.opentype.OpenTypeFont; -class Scaler +class HintScaler { int xScale; @@ -48,5 +48,6 @@ class Scaler int yScale; int yDelta; OpenTypeFont face; - + int renderMode; + } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Latin.java b/libjava/classpath/gnu/java/awt/font/autofit/Latin.java index 0352b41a45a..8951e8b19db 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/Latin.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/Latin.java @@ -39,8 +39,11 @@ exception statement from your version. */ package gnu.java.awt.font.autofit; import java.awt.geom.AffineTransform; +import java.util.HashSet; import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Fixed; +import gnu.java.awt.font.opentype.truetype.Point; import gnu.java.awt.font.opentype.truetype.Zone; /** @@ -50,12 +53,476 @@ class Latin implements Script, Constants { - private static final int MAX_WIDTHS = 16; + static final int MAX_WIDTHS = 16; - public void applyHints(GlyphHints hints, ScriptMetrics metrics) + private final static int MAX_TEST_CHARS = 12; + + /** + * The types of the 6 blue zones. + */ + private static final int CAPITAL_TOP = 0; + private static final int CAPITAL_BOTTOM = 1; + private static final int SMALL_F_TOP = 2; + private static final int SMALL_TOP = 3; + private static final int SMALL_BOTTOM = 4; + private static final int SMALL_MINOR = 5; + static final int BLUE_MAX = 6; + + /** + * The test chars for the blue zones. + * + * @see #initBlues(LatinMetrics, OpenTypeFont) + */ + private static final String[] TEST_CHARS = + new String[]{"THEZOCQS", "HEZLOCUS", "fijkdbh", + "xzroesc", "xzroesc", "pqgjy"}; + + public void applyHints(GlyphHints hints, Zone outline, ScriptMetrics metrics) + { + hints.reload(outline); + hints.rescale(metrics); + if (hints.doHorizontal()) + { + detectFeatures(hints, DIMENSION_HORZ); + } + if (hints.doVertical()) + { + detectFeatures(hints, DIMENSION_VERT); + computeBlueEdges(hints, (LatinMetrics) metrics); + } + // Grid-fit the outline. + for (int dim = 0; dim < DIMENSION_MAX; dim++) + { + if (dim == DIMENSION_HORZ && hints.doHorizontal() + || dim == DIMENSION_VERT && hints.doVertical()) + { + hintEdges(hints, dim); + if (hints.doAlignEdgePoints()) + hints.alignEdgePoints(dim); + if (hints.doAlignStrongPoints()) + hints.alignStrongPoints(dim); + if (hints.doAlignWeakPoints()) + hints.alignWeakPoints(dim); + + } + } + // FreeType does a save call here. I guess that's not needed as we operate + // on the live glyph data anyway. + } + + private void hintEdges(GlyphHints hints, int dim) + { + AxisHints axis = hints.axis[dim]; + Edge[] edges = axis.edges; + int numEdges = axis.numEdges; + Edge anchor = null; + int hasSerifs = 0; + + // We begin by aligning all stems relative to the blue zone if + // needed -- that's only for horizontal edges. + if (dim == DIMENSION_VERT) + { + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + if ((edge.flags & Segment.FLAG_EDGE_DONE) != 0) + continue; + + Width blue = edge.blueEdge; + Edge edge1 = null; + Edge edge2 = edge.link; + if (blue != null) + { + edge1 = edge; + } + else if (edge2 != null && edge2.blueEdge != null) + { + blue = edge2.blueEdge; + edge1 = edge2; + edge2 = edge; + } + if (edge1 == null) + continue; + + edge1.pos = blue.fit; + edge1.flags |= Segment.FLAG_EDGE_DONE; + + if (edge2 != null && edge2.blueEdge == null) + { + alignLinkedEdge(hints, dim, edge1, edge2); + edge2.flags |= Segment.FLAG_EDGE_DONE; + } + if (anchor == null) + anchor = edge; + } + } + + // Now we will align all stem edges, trying to maintain the + // relative order of stems in the glyph. + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + if ((edge.flags & Segment.FLAG_EDGE_DONE) != 0) + continue; + Edge edge2 = edge.link; + if (edge2 == null) + { + hasSerifs++; + continue; + } + // Now align the stem. + // This should not happen, but it's better to be safe. + if (edge2.blueEdge != null || axis.getEdgeIndex(edge2) < e) + { + alignLinkedEdge(hints, dim, edge2, edge); + edge.flags |= Segment.FLAG_EDGE_DONE; + continue; + } + + if (anchor == null) + { + int orgLen = edge2.opos - edge.opos; + int curLen = computeStemWidth(hints, dim, orgLen, edge.flags, + edge2.flags); + int uOff, dOff, orgCenter, curPos1, error1, error2; + if (curLen <= 64) // < 1 Pixel. + { + uOff = 32; + dOff = 32; + } + else + { + uOff = 38; + dOff = 26; + } + if (curLen < 96) + { + orgCenter = edge.opos + (orgLen >> 1); + curPos1 = Utils.pixRound(orgCenter); + error1 = orgCenter - (curPos1 - uOff); + if (error1 < 0) + error1 = -error1; + error2 = orgCenter - (curPos1 + dOff); + if (error2 < 0) + error2 = -error2; + if (error1 < error2) + { + curPos1 -= uOff; + } + else + { + curPos1 += dOff; + } + edge.pos = curPos1 - curLen / 2; + edge2.pos = curPos1 + curLen / 2; + } + else + { + edge.pos = Utils.pixRound(edge.opos); + } + anchor = edge; + edge.flags |= Segment.FLAG_EDGE_DONE; + alignLinkedEdge(hints, dim, edge, edge2); + } + else + { + int aDiff = edge.opos - anchor.opos; + int orgPos = anchor.pos + aDiff; + int orgLen = edge2.opos - edge.opos; + int orgCenter = orgPos + (orgLen >> 1); + int curLen = computeStemWidth(hints, dim, orgLen, edge.flags, + edge2.flags); + //System.err.println("stem width: " + curLen); + if (curLen < 96) + { + int uOff, dOff; + int curPos1 = Utils.pixRound(orgCenter); + if (curLen <= 64) + { + uOff = 32; + dOff = 32; + } + else + { + uOff = 38; + dOff = 26; + } + int delta1 = orgCenter - (curPos1 - uOff); + if (delta1 < 0) + delta1 = -delta1; + int delta2 = orgCenter - (curPos1 + dOff); + if (delta2 < 0) + delta2 = -delta2; + if (delta1 < delta2) + { + curPos1 -= uOff; + } + else + { + curPos1 += dOff; + } + edge.pos = curPos1 - curLen / 2; + edge2.pos = curPos1 + curLen / 2; + } + else + { + orgPos = anchor.pos + (edge.opos - anchor.opos); + orgLen = edge2.opos - edge.opos; + orgCenter = orgPos + (orgLen >> 1); + curLen = computeStemWidth(hints, dim, orgLen, edge.flags, + edge2.flags); + int curPos1 = Utils.pixRound(orgPos); + int delta1 = curPos1 + (curLen >> 1) - orgCenter; + if (delta1 < 0) + delta1 = -delta1; + int curPos2 = Utils.pixRound(orgPos + orgLen) - curLen; + int delta2 = curPos2 + (curLen >> 1) - orgCenter; + if (delta2 < 0) + delta2 = -delta2; + edge.pos = (delta1 < delta2) ? curPos1 : curPos2; + edge2.pos = edge.pos + curLen; + } + edge.flags |= Segment.FLAG_EDGE_DONE; + edge2.flags |= Segment.FLAG_EDGE_DONE; + + if (e > 0 && edge.pos < edges[e - 1].pos) + { + edge.pos = edges[e - 1].pos; + } + } + } + // TODO: Implement the lowercase m symmetry thing. + + // Now we hint the remaining edges (serifs and singles) in order + // to complete our processing. + if (hasSerifs > 0 || anchor == null) + { + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + if ((edge.flags & Segment.FLAG_EDGE_DONE) != 0) + continue; + if (edge.serif != null) + { + alignSerifEdge(hints, edge.serif, edge); + } + else if (anchor == null) + { + edge.pos = Utils.pixRound(edge.opos); + anchor = edge; + } + else + { + edge.pos = anchor.pos + + Utils.pixRound(edge.opos - anchor.opos); + } + edge.flags |= Segment.FLAG_EDGE_DONE; + + if (e > 0 && edge.pos < edges[e - 1].pos) + { + edge.pos = edges[e - 1].pos; + } + if (e + 1 < numEdges + && (edges[e + 1].flags & Segment.FLAG_EDGE_DONE) != 0 + && edge.pos > edges[e + 1].pos) + { + edge.pos = edges[e + 1].pos; + } + } + } + + // Debug: print all hinted edges. + // System.err.println("hinted edges: " ); + // for (int i = 0; i < numEdges; i++) + // { + // System.err.println("edge#" + i + ": " + edges[i]); + // } + } + + private void alignSerifEdge(GlyphHints hints, Edge base, Edge serif) + { + serif.pos = base.pos + (serif.opos - base.opos); + } + + private int computeStemWidth(GlyphHints hints, int dim, int width, + int baseFlags, int stemFlags) + { + LatinMetrics metrics = (LatinMetrics) hints.metrics; + LatinAxis axis = metrics.axis[dim]; + int dist = width; + int sign = 0; + boolean vertical = dim == DIMENSION_VERT; + if (! doStemAdjust(hints)) + return width; + if (dist < 0) + { + dist = -width; + sign = 1; + } + if ((vertical && ! doVertSnap(hints)) || ! vertical && ! doHorzSnap(hints)) + { + // Smooth hinting process. Very lightly quantize the stem width. + // Leave the widths of serifs alone. + if ((stemFlags & Segment.FLAG_EDGE_SERIF) != 0 && vertical + && dist < 3 * 64) + { + return doneWidth(dist, sign); + } + else if ((baseFlags & Segment.FLAG_EDGE_ROUND) != 0) + { + if (dist < 80) + dist = 64; + } + else if (dist < 56) + { + dist = 56; + } + if (axis.widthCount > 0) + { + int delta; + if (axis.widthCount > 0) + { + delta = dist - axis.widths[0].cur; + if (delta < 0) + { + delta = -delta; + } + if (delta < 40) + { + dist = axis.widths[0].cur; + if (dist < 48) + dist = 48; + return doneWidth(dist, sign); + } + } + if (dist < 3 * 64) // < 3 pixels. + { + delta = dist & 63; + dist &= -64; + if (delta < 10) + dist += delta; + else if (delta < 32) + dist += 10; + else if (delta < 54) + dist += 54; + else + dist += delta; + + } + else + { + dist = (dist + 32) & ~63; + } + } + } + else + { + // Strong hinting process: Snap the stem width to integer pixels. + dist = snapWidth(axis.widths, axis.widthCount, dist); + if (vertical) + { + // In the case of vertical hinting, always round + // the stem heights to integer pixels. + if (dist >= 64) + dist = (dist + 16) & ~63; + else + dist = 64; + } + else + { + if (doMono(hints)) + { + // Monochrome horizontal hinting: Snap widths to integer pixels + // with a different threshold. + if (dist < 64) + dist = 64; + else + dist = (dist + 32) & ~63; + } + else + { + // For anti-aliased hinting, we adopt a more subtle + // approach: We strengthen small stems, round those stems + // whose size is between 1 and 2 pixels to an integer, + // otherwise nothing. + if (dist < 48) + dist = (dist + 64) >> 1; + else if (dist < 128) + dist = (dist + 22) & ~63; + else + // Round otherwise to prevent color fringes in LCD mode. + dist = (dist + 32) & ~63; + } + } + } + return doneWidth(dist, sign); + } + + private boolean doMono(GlyphHints hints) + { + return true; + } + + private int snapWidth(Width[] widths, int count, int width) + { + int best = 64 + 32 + 2; + int reference = width; + for (int n = 0; n < count; n++) + { + int w = widths[n].cur; + int dist = width - w; + if (dist < 0) + dist = -dist; + if (dist < best) + { + best = dist; + reference = w; + } + } + int scaled = Utils.pixRound(reference); + if (width >= reference) + { + if (width < scaled + 48) + width = reference; + } + else + { + if (width > scaled + 48) + width = reference; + } + return width; + } + + private int doneWidth(int w, int s) + { + if (s == 1) + w = -w; + return w; + } + + private boolean doVertSnap(GlyphHints hints) + { + // TODO Auto-generated method stub + return true; + } + + private boolean doHorzSnap(GlyphHints hints) { // TODO Auto-generated method stub + return true; + } + private boolean doStemAdjust(GlyphHints hints) + { + // TODO Auto-generated method stub + return true; + } + + private void alignLinkedEdge(GlyphHints hints, int dim, Edge base, Edge stem) + { + int dist = stem.opos - base.opos; + int fitted = computeStemWidth(hints, dim, dist, base.flags, stem.flags); + stem.pos = base.pos + fitted; } public void doneMetrics(ScriptMetrics metrics) @@ -99,10 +566,119 @@ class Latin initBlues(lm, face); } - public void scaleMetrics(ScriptMetrics metrics) + public void scaleMetrics(ScriptMetrics metrics, HintScaler scaler) { - // TODO Auto-generated method stub + LatinMetrics lm = (LatinMetrics) metrics; + lm.scaler.renderMode = scaler.renderMode; + lm.scaler.face = scaler.face; + scaleMetricsDim(lm, scaler, DIMENSION_HORZ); + scaleMetricsDim(lm, scaler, DIMENSION_VERT); + } + private void scaleMetricsDim(LatinMetrics lm, HintScaler scaler, int dim) + { + int scale; + int delta; + if (dim == DIMENSION_HORZ) + { + scale = scaler.xScale; + delta = scaler.xDelta; + } + else + { + scale = scaler.yScale; + delta = scaler.yDelta; + } + LatinAxis axis = lm.axis[dim]; + if (axis.orgScale == scale && axis.orgDelta == delta) + // No change, no need to adjust. + return; + axis.orgScale = scale; + axis.orgDelta = delta; + + // Correct X and Y scale to optimize the alignment of the top small + // letters to the pixel grid. + LatinAxis axis2 = lm.axis[DIMENSION_VERT]; + LatinBlue blue = null; +// for (int nn = 0; nn < axis2.blueCount; nn++) +// { +// if ((axis2.blues[nn].flags & LatinBlue.FLAG_ADJUSTMENT) != 0) +// { +// blue = axis2.blues[nn]; +// break; +// } +// } +// if (blue != null) +// { +// int scaled = Fixed.mul16(blue.shoot.org, scaler.yScale); +// int fitted = Utils.pixRound(scaled); +// if (scaled != fitted) +// { +// if (dim == DIMENSION_HORZ) +// { +// if (fitted < scaled) +// { +// scale -= scale / 50; +// } +// } +// else +// { +// scale = Utils.mulDiv(scale, fitted, scaled); +// } +// } +// } + axis.scale = scale; + axis.delta = delta; + if (dim == DIMENSION_HORZ) + { + lm.scaler.xScale = scale; + lm.scaler.xDelta = delta; + } + else + { + lm.scaler.yScale = scale; + lm.scaler.yDelta = delta; + } + // Scale the standard widths. + for (int nn = 0; nn < axis.widthCount; nn++) + { + Width w = axis.widths[nn]; + w.cur = Fixed.mul16(w.org, scale); + w.fit = w.cur; + } + // Scale blue zones. + if (dim == DIMENSION_VERT) + { + for (int nn = 0; nn < axis.blueCount; nn++) + { + blue = axis.blues[nn]; + blue.ref.cur = Fixed.mul16(blue.ref.org, scale) + delta; + blue.ref.fit = blue.ref.cur; + blue.shoot.cur = Fixed.mul16(blue.ref.org, scale) + delta; + blue.flags &= ~LatinBlue.FLAG_BLUE_ACTIVE; + // A blue zone is only active if it is less than 3/4 pixels tall. + int dist = Fixed.mul16(blue.ref.org - blue.shoot.org, scale); + if (dist <= 48 && dist >= -48) + { + int delta1 = blue.shoot.org - blue.ref.org; + int delta2 = delta1; + if (delta1 < 0) + delta2 = -delta2; + delta2 = Fixed.mul16(delta2, scale); + if (delta2 < 32) + delta2 = 0; + else if (delta2 < 64) + delta2 = 32 + (((delta2 - 32) + 16) & ~31); + else + delta2 = Utils.pixRound(delta2); + if (delta1 < 0) + delta2 = -delta2; + blue.ref.fit = Utils.pixRound(blue.ref.cur); + blue.shoot.fit = blue.ref.fit + delta2; + blue.flags |= LatinBlue.FLAG_BLUE_ACTIVE; + } + } + } } /** @@ -118,12 +694,9 @@ class Latin metrics.axis[DIMENSION_HORZ].widthCount = 0; metrics.axis[DIMENSION_VERT].widthCount = 0; int glyphIndex = face.getGlyph(ch); - // TODO: Avoid that AffineTransform constructor and change - // getRawGlyphOutline() to accept null or remove that parameter altogether. - // Consider this when the thing is done and we know what we need that for. - Zone outline = face.getRawGlyphOutline(glyphIndex, new AffineTransform()); + Zone outline = face.getRawGlyphOutline(glyphIndex, IDENTITY); LatinMetrics dummy = new LatinMetrics(); - Scaler scaler = dummy.scaler; + HintScaler scaler = dummy.scaler; dummy.unitsPerEm = metrics.unitsPerEm; scaler.xScale = scaler.yScale = 10000; scaler.xDelta = scaler.yDelta = 0; @@ -135,20 +708,24 @@ class Latin LatinAxis axis = metrics.axis[dim]; AxisHints axHints = hints.axis[dim]; int numWidths = 0; - hints.computeSegments(dim); - hints.linkSegments(dim); + computeSegments(hints, dim); + linkSegments(hints, dim); Segment[] segs = axHints.segments; + HashSet<Segment> touched = new HashSet<Segment>(); for (int i = 0; i < segs.length; i++) { Segment seg = segs[i]; Segment link = seg.link; - if (link != null && link.link == seg && link.index > i) + if (link != null && link.link == seg && ! touched.contains(link)) { int dist = Math.abs(seg.pos - link.pos); if (numWidths < MAX_WIDTHS) - axis.widths[numWidths++].org = dist; + axis.widths[numWidths++] = new Width(dist); } + touched.add(seg); } + Utils.sort(numWidths, axis.widths); + axis.widthCount = numWidths; } for (int dim = 0; dim < DIMENSION_MAX; dim++) { @@ -159,6 +736,78 @@ class Latin } } + void linkSegments(GlyphHints hints, int dim) + { + AxisHints axis = hints.axis[dim]; + Segment[] segments = axis.segments; + int numSegs = axis.numSegments; + int majorDir = axis.majorDir; + int lenThreshold = constant((LatinMetrics) hints.metrics, 8); + lenThreshold = Math.min(1, lenThreshold); + int lenScore = constant((LatinMetrics) hints.metrics, 3000); + for (int i1 = 0; i1 < numSegs; i1++) + { + Segment seg1 = segments[i1]; + // The fake segments are introduced to hint the metrics. + // Never link them to anything. + if (seg1.first == seg1.last || seg1.dir != majorDir) + continue; + for (int i2 = 0; i2 < numSegs; i2++) + { + Segment seg2 = segments[i2]; + if (seg2 != seg1 && seg1.dir + seg2.dir == 0) + { + int pos1 = seg1.pos; + int pos2 = seg2.pos; + // The vertical coords are swapped compared to how FT handles + // this. + int dist = dim == DIMENSION_VERT ? pos1 - pos2 : pos2 - pos1; + if (dist >= 0) + { + int min = seg1.minPos; + int max = seg1.maxPos; + int len, score; + if (min < seg2.minPos) + min = seg2.minPos; + if (max > seg2.maxPos) + max = seg2.maxPos; + len = max - min; + if (len > lenThreshold) + { + score = dist + lenScore / len; + if (score < seg1.score) + { + seg1.score = score; + seg1.link = seg2; + } + if (score < seg2.score) + { + seg2.score = score; + seg2.link = seg1; + } + } + } + } + } + } + for (int i1 = 0; i1 < numSegs; i1++) + { + Segment seg1 = segments[i1]; + Segment seg2 = seg1.link; + if (seg2 != null) + { + seg2.numLinked++; + if (seg2.link != seg1) + { + seg1.link = null; + seg1.serif = seg2.link; + } + } + // Uncomment to show all segments. + // System.err.println("segment#" + i1 + ": " + seg1); + } + } + /** * Initializes the blue zones of the font. * @@ -167,11 +816,548 @@ class Latin */ private void initBlues(LatinMetrics metrics, OpenTypeFont face) { - // TODO: Implement. + int[] flats = new int[MAX_TEST_CHARS]; + int[] rounds = new int[MAX_TEST_CHARS]; + int numFlats; + int numRounds; + LatinBlue blue; + LatinAxis axis = metrics.axis[DIMENSION_VERT]; + // We compute the blues simply by loading each character in the test + // strings, then compute its topmost or bottommost points. + for (int bb = 0; bb < BLUE_MAX; bb++) + { + String p = TEST_CHARS[bb]; + int blueRef; + int blueShoot; + numFlats = 0; + numRounds = 0; + for (int i = 0; i < p.length(); i++) + { + // Load the character. + int glyphIndex = face.getGlyph(p.charAt(i)); + Zone glyph = + face.getRawGlyphOutline(glyphIndex, IDENTITY); + + // Now compute the min and max points. + int numPoints = glyph.getSize() - 4; // 4 phantom points. + Point[] points = glyph.getPoints(); + Point point = points[0]; + int extremum = 0; + int index = 1; + if (isTopBlue(bb)) + { + for (; index < numPoints; index++) + { + point = points[index]; + // We have the vertical direction swapped. The higher + // points have smaller (negative) Y. + if (point.getOrigY() < points[extremum].getOrigY()) + extremum = index; + } + } + else + { + for (; index < numPoints; index++) + { + point = points[index]; + // We have the vertical direction swapped. The higher + // points have smaller (negative) Y. + if (point.getOrigY() > points[extremum].getOrigY()) + extremum = index; + } + } + // Debug, prints out the maxima. + // System.err.println("extremum for " + bb + " / "+ p.charAt(i) + // + ": " + points[extremum]); + + // Now determine if the point is part of a straight or round + // segment. + boolean round; + int idx = extremum; + int first, last, prev, next, end; + int dist; + last = -1; + first = 0; + for (int n = 0; n < glyph.getNumContours(); n++) + { + end = glyph.getContourEnd(n); + // System.err.println("contour end for " + n + ": " + end); + if (end >= idx) + { + last = end; + break; + } + first = end + 1; + } + // Should never happen. + assert last >= 0; + + // Now look for the previous and next points that are not on the + // same Y coordinate. Threshold the 'closeness'. + prev = idx; + next = prev; + do + { + if (prev > first) + prev--; + else + prev = last; + dist = points[prev].getOrigY() - points[extremum].getOrigY(); + if (dist < -5 || dist > 5) + break; + } while (prev != idx); + do + { + if (next < last) + next++; + else + next = first; + dist = points[next].getOrigY() - points[extremum].getOrigY(); + if (dist < -5 || dist > 5) + break; + } while (next != idx); + round = points[prev].isControlPoint() + || points[next].isControlPoint(); + + if (round) + { + rounds[numRounds++] = points[extremum].getOrigY(); + // System.err.println("new round extremum: " + bb + ": " + // + points[extremum].getOrigY()); + } + else + { + flats[numFlats++] = points[extremum].getOrigY(); + // System.err.println("new flat extremum: " + bb + ": " + // + points[extremum].getOrigY()); + } + } + // We have computed the contents of the rounds and flats tables. + // Now determine the reference and overshoot position of the blues -- + // we simply take the median after a simple sort. + Utils.sort(numRounds, rounds); + Utils.sort(numFlats, flats); + blue = axis.blues[axis.blueCount] = new LatinBlue(); + axis.blueCount++; + if (numFlats == 0) + { + blue.ref = blue.shoot = new Width(rounds[numRounds / 2]); + } + else if (numRounds == 0) + { + blue.ref = blue.shoot = new Width(flats[numFlats / 2]); + } + else + { + blue.ref = new Width(flats[numFlats / 2]); + blue.shoot = new Width(rounds[numRounds / 2]); + } + // There are sometimes problems: if the overshoot position of top + // zones is under its reference position, or the opposite for bottom + // zones. We must check everything there and correct problems. + if (blue.shoot != blue.ref) + { + int ref = blue.ref.org; + int shoot = blue.shoot.org; + // Inversed vertical coordinates! + boolean overRef = shoot < ref; + if (isTopBlue(bb) ^ overRef) + { + blue.shoot = blue.ref = new Width((shoot + ref) / 2); + } + } + blue.flags = 0; + if (isTopBlue(bb)) + blue.flags |= LatinBlue.FLAG_TOP; + // The following flag is used later to adjust y and x scales in + // order to optimize the pixel grid alignment of the top small + // letters. + if (bb == SMALL_TOP) + { + blue.flags |= LatinBlue.FLAG_ADJUSTMENT; + } + // Debug: print out the blue zones. + // System.err.println("blue zone #" + bb + ": " + blue); + } } + private static final AffineTransform IDENTITY = new AffineTransform(); + private int constant(LatinMetrics metrics, int c) { return c * (metrics.unitsPerEm / 2048); } + + private void computeSegments(GlyphHints hints, int dim) + { + Point[] points = hints.points; + if (dim == DIMENSION_HORZ) + { + for (int i = 0; i < hints.numPoints; i++) + { + points[i].setU(points[i].getOrigX()); + points[i].setV(points[i].getOrigY()); + } + } + else + { + for (int i = 0; i < hints.numPoints; i++) + { + points[i].setU(points[i].getOrigY()); + points[i].setV(points[i].getOrigX()); + } + } + // Now look at each contour. + AxisHints axis = hints.axis[dim]; + int majorDir = Math.abs(axis.majorDir); + int segmentDir = majorDir; + Point[] contours = hints.contours; + int numContours = hints.numContours; + Segment segment = null; + for (int i = 0; i < numContours; i++) + { + int minPos = 32000; + int maxPos = -32000; + + Point point = contours[i]; + Point last = point.getPrev(); + if (point == last) // Skip singletons. + continue; + if (Math.abs(last.getOutDir()) == majorDir + && Math.abs(point.getOutDir()) == majorDir) + { + // We are already on an edge. Locate its start. + last = point; + while (true) + { + point = point.getPrev(); + if (Math.abs(point.getOutDir()) != majorDir) + { + point = point.getNext(); + break; + } + if (point == last) + break; + } + } + last = point; + boolean passed = false; + boolean onEdge = false; + while (true) + { + int u, v; + if (onEdge) + { + u = point.getU(); + if (u < minPos) + minPos = u; + if (u > maxPos) + maxPos = u; + if (point.getOutDir() != segmentDir || point == last) + { + // Leaving an edge. Record new segment. + segment.last = point; + // (minPos + maxPos) / 2. + segment.pos = (minPos + maxPos) >> 1; + if (segment.first.isControlPoint() + || point.isControlPoint()) + segment.flags |= Segment.FLAG_EDGE_ROUND; + minPos = maxPos = point.getV(); + v = segment.first.getV(); + if (v < minPos) + minPos = v; + if (v > maxPos) + maxPos = v; + segment.minPos = minPos; + segment.maxPos = maxPos; + onEdge = false; + segment = null; + } + } + if (point == last) + { + if (passed) + break; + passed = true; + } + if (! onEdge && Math.abs(point.getOutDir()) == majorDir) + { + // This is the start of a new segment. + segmentDir = point.getOutDir(); + segment = axis.newSegment(); + segment.dir = segmentDir; + segment.flags = Segment.FLAG_EDGE_NORMAL; + minPos = maxPos = point.getU(); + segment.first = point; + segment.last = point; + segment.contour = contours[i]; + segment.score = 32000; + segment.len = 0; + segment.link = null; + onEdge = true; + } + point = point.getNext(); + } + } + + } + + private boolean isTopBlue(int b) + { + return b == CAPITAL_TOP || b == SMALL_F_TOP || b == SMALL_TOP; + } + + private void detectFeatures(GlyphHints hints, int dim) + { + computeSegments(hints, dim); + linkSegments(hints, dim); + computeEdges(hints, dim); + } + + private void computeEdges(GlyphHints hints, int dim) + { + AxisHints axis = hints.axis[dim]; + LatinAxis laxis = ((LatinMetrics) hints.metrics).axis[dim]; + Segment[] segments = axis.segments; + int numSegments = axis.numSegments; + Segment seg; + int upDir; + int scale; + int edgeDistanceThreshold; + axis.numEdges = 0; + scale = dim == DIMENSION_HORZ ? hints.xScale : hints.yScale; + upDir = dim == DIMENSION_HORZ ? DIR_UP : DIR_RIGHT; + + // We will begin by generating a sorted table of edges for the + // current direction. To do so, we simply scan each segment and try + // to find an edge in our table that corresponds to its position. + // + // If no edge is found, we create one and insert a new edge in the + // sorted table. Otherwise, we simply add the segment to the egde's + // list which will be processed in the second step to compute the + // edge's properties. + // + // Note that the edge table is sorted along the segment/edge + // position. + + edgeDistanceThreshold = Fixed.mul16(laxis.edgeDistanceTreshold, scale); + if (edgeDistanceThreshold > 64 / 4) + edgeDistanceThreshold = 64 / 4; + edgeDistanceThreshold = Fixed.div16(edgeDistanceThreshold, scale); + for (int i = 0; i < numSegments; i++) + { + seg = segments[i]; + Edge found = null; + for (int ee = 0; ee < axis.numEdges; ee++) + { + Edge edge = axis.edges[ee]; + int dist = seg.pos - edge.fpos; + if (dist < 0) + dist = -dist; + if (dist < edgeDistanceThreshold) + { + found = edge; + break; + } + } + if (found == null) + { + // Insert new edge in the list and sort according to + // the position. + Edge edge = axis.newEdge(seg.pos); + edge.first = seg; + edge.last = seg; + edge.fpos = seg.pos; + edge.opos = edge.pos = Fixed.mul16(seg.pos, scale); + seg.edgeNext = seg; + seg.edge = edge; + } + else + { + seg.edgeNext = found.first; + found.last.edgeNext = seg; + found.last = seg; + seg.edge = found; + } + } + // Good. We will now compute each edge's properties according to + // segments found on its position. Basically these are: + // - Edge's main direction. + // - Stem edge, serif edge, or both (which defaults to stem edge). + // - Rounded edge, straight or both (which defaults to straight). + // - Link for edge. + + // Now, compute each edge properties. + for (int e = 0; e < axis.numEdges; e++) + { + Edge edge = axis.edges[e]; + // Does it contain round segments? + int isRound = 0; + // Does it contain straight segments? + int isStraight = 0; + // Number of upward segments. + int ups = 0; + // Number of downward segments. + int downs = 0; + + seg = edge.first; + do + { + // Check for roundness of segment. + if ((seg.flags & Segment.FLAG_EDGE_ROUND) != 0) + isRound++; + else + isStraight++; + + // Check for segment direction. + if (seg.dir == upDir) + ups += seg.maxPos - seg.minPos; + else + downs += seg.maxPos - seg.minPos; + + // Check for links. If seg.serif is set, then seg.link must + // be ignored. + boolean isSerif = seg.serif != null && seg.serif.edge != edge; + if (seg.link != null || isSerif) + { + Edge edge2 = edge.link; + Segment seg2 = seg.link; + if (isSerif) + { + seg2 = seg.serif; + edge2 = edge.serif; + } + if (edge2 != null) + { + int edgeDelta = edge.fpos - edge2.fpos; + if (edgeDelta < 0) + edgeDelta = -edgeDelta; + int segDelta = seg.pos - seg2.pos; + if (segDelta < 0) + segDelta = -segDelta; + if (segDelta < edgeDelta) + edge2 = seg2.edge; + } + else + { + edge2 = seg2.edge; + } + if (isSerif) + { + edge.serif = edge2; + edge2.flags |= Segment.FLAG_EDGE_SERIF; + } + else + { + edge.link = edge2; + } + } + seg = seg.edgeNext; + } while (seg != edge.first); + edge.flags = Segment.FLAG_EDGE_NORMAL; + if (isRound > 0 && isRound > isStraight) + edge.flags |= Segment.FLAG_EDGE_ROUND; + + // Set the edge's main direction. + edge.dir = DIR_NONE; + if (ups > downs) + edge.dir = upDir; + else if (ups < downs) + edge.dir = -upDir; + else if (ups == downs) + edge.dir = 0; + + // Gets rid of serif if link is set. This gets rid of many + // unpleasant artifacts. + if (edge.serif != null && edge.link != null) + { + edge.serif = null; + } + + // Debug: Print out all edges. + // System.err.println("edge# " + e + ": " + edge); + } + } + + private void computeBlueEdges(GlyphHints hints, LatinMetrics metrics) + { + AxisHints axis = hints.axis[DIMENSION_VERT]; + Edge[] edges = axis.edges; + int numEdges = axis.numEdges; + LatinAxis latin = metrics.axis[DIMENSION_VERT]; + int scale = latin.scale; + + // Compute which blue zones are active. I.e. have their scaled + // size < 3/4 pixels. + + // For each horizontal edge search the blue zone that is closest. + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + // System.err.println("checking edge: " + edge); + Width bestBlue = null; + int bestDist = Fixed.mul16(metrics.unitsPerEm / 40, scale); + + if (bestDist > 64 / 2) + bestDist = 64 / 2; + for (int bb = 0; bb < BLUE_MAX; bb++) + { + LatinBlue blue = latin.blues[bb]; + // System.err.println("checking blue: " + blue); + // Skip inactive blue zones, i.e. those that are too small. + if ((blue.flags & LatinBlue.FLAG_BLUE_ACTIVE) == 0) + continue; + // If it is a top zone, check for right edges. If it is a bottom + // zone, check for left edges. + boolean isTopBlue = (blue.flags & LatinBlue.FLAG_TOP) != 0; + boolean isMajorDir = edge.dir == axis.majorDir; + + // If it is a top zone, the edge must be against the major + // direction. If it is a bottom zone it must be in the major + // direction. + if (isTopBlue ^ isMajorDir) + { + int dist = edge.fpos - blue.ref.org; + if (dist < 0) + dist = -dist; + dist = Fixed.mul16(dist, scale); + if (dist < bestDist) + { + bestDist = dist; + bestBlue = blue.ref; + } + + // Now, compare it to the overshoot position if the edge is + // rounded, and if the edge is over the reference position of + // a top zone, or under the reference position of a bottom + // zone. + if ((edge.flags & Segment.FLAG_EDGE_ROUND) != 0 && dist != 0) + { + // Inversed vertical coordinates! + boolean isUnderRef = edge.fpos > blue.ref.org; + if (isTopBlue ^ isUnderRef) + { + blue = latin.blues[bb]; // Needed? + dist = edge.fpos - blue.shoot.org; + if (dist < 0) + dist = -dist; + dist = Fixed.mul16(dist, scale); + if (dist < bestDist) + { + bestDist = dist; + bestBlue = blue.shoot; + } + } + } + + } + } + if (bestBlue != null) + { + edge.blueEdge = bestBlue; + // Debug: Print out the blue edges. + // System.err.println("blue edge for: " + edge + ": " + bestBlue); + } + } + } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java index 8ca1e6d9ed2..9237d0ee5b1 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java @@ -49,5 +49,14 @@ class LatinAxis int widthCount; Width[] widths; - float edgeDistanceTreshold; + int edgeDistanceTreshold; + LatinBlue[] blues; + int blueCount; + int orgDelta; + int orgScale; + LatinAxis() + { + widths = new Width[Latin.MAX_WIDTHS]; + blues = new LatinBlue[Latin.BLUE_MAX]; + } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java new file mode 100644 index 00000000000..694fb24fe07 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java @@ -0,0 +1,59 @@ +/* LatinBlue.java -- FIXME: briefly describe file purpose + 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.autofit; + +public class LatinBlue +{ + static final int FLAG_BLUE_ACTIVE = 1 << 0; + static final int FLAG_TOP = 1 << 1; + static final int FLAG_ADJUSTMENT = 1 << 2; + Width ref; + Width shoot; + int flags; + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[BlueZone]"); + s.append(" ref: "); + s.append(ref.org); + s.append(", shoot: "); + s.append(shoot.org); + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java index cd955348b37..33fc63ad4ba 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java @@ -38,6 +38,8 @@ exception statement from your version. */ package gnu.java.awt.font.autofit; +import gnu.java.awt.font.opentype.OpenTypeFont; + /** * Latin specific metrics data. */ @@ -48,4 +50,17 @@ class LatinMetrics LatinAxis[] axis; int unitsPerEm; + + LatinMetrics() + { + super(); + axis = new LatinAxis[Constants.DIMENSION_MAX]; + axis[Constants.DIMENSION_HORZ] = new LatinAxis(); + axis[Constants.DIMENSION_VERT] = new LatinAxis(); + } + LatinMetrics(OpenTypeFont face) + { + this(); + unitsPerEm = face.unitsPerEm; + } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Script.java b/libjava/classpath/gnu/java/awt/font/autofit/Script.java index 3b353010f2d..c223f0a26af 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/Script.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/Script.java @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.awt.font.autofit; import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Zone; /** * Defines script specific methods for the auto fitter. @@ -51,12 +52,11 @@ interface Script */ void initMetrics(ScriptMetrics metrics, OpenTypeFont face); - void scaleMetrics(ScriptMetrics metrics/* , scaler, map this */); + void scaleMetrics(ScriptMetrics metrics , HintScaler scaler); void doneMetrics(ScriptMetrics metrics); void initHints(GlyphHints hints, ScriptMetrics metrics); - void applyHints(GlyphHints hints, /* some outline object, */ - ScriptMetrics metrics); + void applyHints(GlyphHints hints, Zone outline, ScriptMetrics metrics); } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java b/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java index 77c815ae59d..984a06daee4 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java @@ -45,5 +45,9 @@ class ScriptMetrics { Script script; - Scaler scaler; + HintScaler scaler; + ScriptMetrics() + { + scaler = new HintScaler(); + } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Segment.java b/libjava/classpath/gnu/java/awt/font/autofit/Segment.java index 32032a48fcc..640e82ce2e9 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/Segment.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/Segment.java @@ -38,10 +38,58 @@ exception statement from your version. */ package gnu.java.awt.font.autofit; +import gnu.java.awt.font.opentype.truetype.Point; + class Segment { + static final int FLAG_EDGE_NORMAL = 0; + static final int FLAG_EDGE_ROUND = 1; + static final int FLAG_EDGE_SERIF = 2; + static final int FLAG_EDGE_DONE = 4; + int dir; + int flags; Segment link; - int index; + Segment serif; + int numLinked; int pos; + Point first; + Point last; + Point contour; + int minPos; + int maxPos; + int score; + int len; + Segment edgeNext; + Edge edge; + + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[Segment] id: "); + s.append(hashCode()); + s.append(", len:"); + s.append(len); + s.append(", round: "); + s.append(((flags & FLAG_EDGE_ROUND) != 0)); + s.append(", dir: "); + s.append(dir); + s.append(", pos: "); + s.append(pos); + s.append(", minPos: "); + s.append(minPos); + s.append(", maxPos: "); + s.append(maxPos); + s.append(", first: "); + s.append(first); + s.append(", last: "); + s.append(last); + s.append(", contour: "); + s.append(contour); + s.append(", link: "); + s.append(link == null ? "null" : link.hashCode()); + s.append(", serif: "); + s.append(serif == null ? "null" : serif.hashCode()); + return s.toString(); + } } diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Utils.java b/libjava/classpath/gnu/java/awt/font/autofit/Utils.java new file mode 100644 index 00000000000..4df4705a8d1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Utils.java @@ -0,0 +1,255 @@ +/* Utils.java -- A collection of utility functions for the autofitter + 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.autofit; + +import gnu.java.awt.font.opentype.truetype.Fixed; + +/** + * A collection of utility methods used all around the auto fitter. + */ +class Utils + implements Constants +{ + + private static final int ATAN_BITS = 8; + private static final byte[] ATAN = new byte[] + { + 0, 0, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 12, 12, 12, + 13, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 16, 16, 16, 17, 17, 17, + 18, 18, 18, 18, 19, 19, 19, 20, + 20, 20, 21, 21, 21, 21, 22, 22, + 22, 23, 23, 23, 24, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 26, 27, + 27, 27, 28, 28, 28, 28, 29, 29, + 29, 30, 30, 30, 30, 31, 31, 31, + 31, 32, 32, 32, 33, 33, 33, 33, + 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 38, + 38, 38, 38, 39, 39, 39, 39, 40, + 40, 40, 40, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, + 46, 46, 46, 46, 46, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 49, + 49, 49, 50, 50, 50, 50, 50, 51, + 51, 51, 51, 51, 52, 52, 52, 52, + 52, 53, 53, 53, 53, 53, 54, 54, + 54, 54, 54, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 58, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 59, 60, 60, + 60, 60, 60, 61, 61, 61, 61, 61, + 61, 62, 62, 62, 62, 62, 62, 63, + 63, 63, 63, 63, 63, 64, 64, 64 + }; + + private static final int ANGLE_PI = 256; + private static final int ANGLE_PI2 = ANGLE_PI / 2; + private static final int ANGLE_PI4 = ANGLE_PI / 4; + private static final int ANGLE_2PI = ANGLE_PI * 2; + + /** + * Computes the direction constant for the specified vector. The vector is + * given as differential value already. + * + * @param dx the x vector + * @param dy the y vector + * + * @return the direction of that vector, or DIR_NONE, if that vector is not + * approximating against one of the major axises + */ + static int computeDirection(int dx, int dy) + { + int dir = DIR_NONE; + if (dx < 0) + { + if (dy < 0) + { + if (-dx * 12 < -dy) + dir = DIR_UP; + else if (-dy * 12 < -dx) + dir = DIR_LEFT; + } + else // dy >= 0 . + { + if (-dx * 12 < dy) + dir = DIR_DOWN; + else if (dy * 12 < -dx) + dir = DIR_LEFT; + } + } + else // dx >= 0 . + { + if (dy < 0) + { + if (dx * 12 < -dy) + dir = DIR_UP; + else if (-dy * 12 < dx) + dir = DIR_RIGHT; + } + else // dy >= 0 . + { + if (dx * 12 < dy) + dir = DIR_DOWN; + else if (dy * 12 < dx) + dir = DIR_RIGHT; + } + } + return dir; + } + + public static int atan(int dx, int dy) + { + int angle; + // Trivial cases. + if (dy == 0) + { + angle = 0; + if (dx < 0) + angle = ANGLE_PI; + return angle; + } + else if (dx == 0) + { + angle = ANGLE_PI2; + if (dy < 0) + angle = - ANGLE_PI2; + return angle; + } + + + angle = 0; + if (dx < 0) + { + dx = -dx; + dy = -dy; + angle = ANGLE_PI; + } + if (dy < 0) + { + int tmp = dx; + dx = -dy; + dy = tmp; + angle -= ANGLE_PI2; + } + if (dx == 0 && dy == 0) + return 0; + + if (dx == dy) + angle += ANGLE_PI4; + else if (dx > dy) + { + angle += ATAN[Fixed.div(dy, dx) << (ATAN_BITS - 6)]; + } + else + { + angle += ANGLE_PI2 - ATAN[Fixed.div(dx, dy) << (ATAN_BITS - 6)]; + } + + if (angle > ANGLE_PI) + angle -= ANGLE_2PI; + return angle; + } + + public static int angleDiff(int ang1, int ang2) + { + int delta = ang2 - ang1; + delta %= ANGLE_2PI; + if (delta < 0) + delta += ANGLE_2PI; + if (delta > ANGLE_PI) + delta -= ANGLE_2PI; + return delta; + } + + static void sort(int num, int[] array) + { + int swap; + for (int i = 1; i < num; i++) + { + for (int j = i; j > 0; j--) + { + if (array[j] > array[j - 1]) + break; + swap = array[j]; + array[j] = array[j - 1]; + array[j - 1] = swap; + } + } + } + + static void sort(int num, Width[] array) + { + Width swap; + for (int i = 1; i < num; i++) + { + for (int j = 1; j > 0; j--) + { + if (array[j].org > array[j - 1].org) + break; + swap = array[j]; + array[j] = array[j - 1]; + array[j - 1] = swap; + } + } + } + + static int pixRound(int val) + { + return pixFloor(val + 32); + } + + static int pixFloor(int val) + { + return val & ~63; + } + + public static int mulDiv(int a, int b, int c) + { + long prod = a * b; + long div = (prod / c); + return (int) div; + } + +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Width.java b/libjava/classpath/gnu/java/awt/font/autofit/Width.java index d4d540069ee..c890cf3de3d 100644 --- a/libjava/classpath/gnu/java/awt/font/autofit/Width.java +++ b/libjava/classpath/gnu/java/awt/font/autofit/Width.java @@ -43,4 +43,20 @@ public class Width int org; int cur; int fit; + Width(int dist) + { + org = dist; + } + + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[Width] org: "); + s.append(org); + s.append(", cur: "); + s.append(cur); + s.append(", fit: "); + s.append(fit); + return s.toString(); + } } diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java b/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java new file mode 100644 index 00000000000..9758a2896b7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java @@ -0,0 +1,63 @@ +/* Hinter.java -- The interface to a hinting implementation + 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.opentype.truetype.Zone; + +/** + * The interface to a hinting implementation. + */ +public interface Hinter +{ + /** + * Initializes the hinter. + * + * @param face the font for which the hinter should be used + */ + void init(OpenTypeFont face); + + /** + * Hints the specified outline. + * + * @param outline the outline to hint + */ + void applyHints(Zone outline); + + void setFlags(int flags); +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java index efc30811f7b..a270ce7d96d 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java @@ -51,6 +51,7 @@ import java.util.Locale; import gnu.java.awt.font.FontDelegate; import gnu.java.awt.font.GNUGlyphVector; +import gnu.java.awt.font.autofit.AutoHinter; import gnu.java.awt.font.opentype.truetype.TrueTypeScaler; import gnu.java.awt.font.opentype.truetype.Zone; @@ -146,7 +147,8 @@ public final class OpenTypeFont */ private GlyphNamer glyphNamer; - + private Hinter hinter; + /** * Constructs an OpenType or TrueType font. * @@ -579,6 +581,9 @@ public final class OpenTypeFont FontRenderContext frc, CharacterIterator ci) { + // Initialize hinter if necessary. + checkHinter(FontDelegate.FLAG_FITTED); + CharGlyphMap cmap; int numGlyphs; int[] glyphs; @@ -689,13 +694,15 @@ public final class OpenTypeFont float pointSize, AffineTransform transform, boolean antialias, - boolean fractionalMetrics) + boolean fractionalMetrics, + int flags) { /* The synchronization is needed because the scaler is not * synchronized. */ + checkHinter(flags); return scaler.getOutline(glyph, pointSize, transform, - antialias, fractionalMetrics); + antialias, fractionalMetrics, hinter, flags); } /** @@ -837,4 +844,29 @@ public final class OpenTypeFont c[3] = (char) (tag & 0xff); return new String(c); } + + /** + * Checks if a hinter is installed and installs one when not. + */ + private void checkHinter(int flags) + { + // When another hinting impl gets added (maybe a true TrueType hinter) + // then add some options here. The Hinter interface might need to be + // tweaked. + if (hinter == null) + { + try + { + hinter = new AutoHinter(); + hinter.init(this); + } + catch (Exception ex) + { + // Protect from problems inside hinter. + hinter = null; + ex.printStackTrace(); + } + } + hinter.setFlags(flags); + } } diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java index 83a31c576c7..c7582b66657 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java @@ -90,7 +90,8 @@ public abstract class Scaler float pointSize, AffineTransform transform, boolean antialias, - boolean fractionalMetrics); + boolean fractionalMetrics, + Hinter hinter, int type); /** diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java index 5d81c5d2e6a..287593e439c 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java @@ -48,7 +48,7 @@ package gnu.java.awt.font.opentype.truetype; * * @author Sascha Brawer (brawer@dandelis.ch) */ -final class Fixed +public final class Fixed { public static final int ONE = 1<<6; @@ -69,14 +69,21 @@ final class Fixed return (int) ((((long) a) * b) >> 6); } + public static int mul16(int a, int b) + { + return (int) ((((long) a) * b) >> 16); + } public static int div(int a, int b) { return (int) ((((long) a) << 6) / b); } + public static int div16(int a, int b) + { + return (int) ((((long) a) << 16) / b); + } - public static int ceil(int a) { return (a + 63) & -64; @@ -119,7 +126,10 @@ final class Fixed { return ((float) f) / 64; } - + public static float floatValue16(int f) + { + return ((float) f) / 65536; + } public static double doubleValue(int f) { @@ -138,6 +148,10 @@ final class Fixed return (int) (d * 64); } + public static int valueOf16(double d) + { + return (int) (d * (1 << 16)); + } /** * Makes a string representation of a fixed-point number. diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java index 3733afe92d8..249a87dd403 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java @@ -38,6 +38,8 @@ exception statement from your version. */ package gnu.java.awt.font.opentype.truetype; +import gnu.java.awt.font.opentype.Hinter; + import java.awt.geom.AffineTransform; import java.nio.ByteBuffer; @@ -112,17 +114,17 @@ final class GlyphLoader double pointSize, AffineTransform transform, boolean antialias, - Zone glyphZone) + Zone glyphZone, Hinter hinter) { glyphZone.setNumPoints(4); loadSubGlyph(glyphIndex, pointSize, transform, antialias, glyphZone, - 0, 0); + 0, 0, hinter); } public void loadGlyph(int glyphIndex, AffineTransform transform, - Zone glyphZone) + Zone glyphZone, Hinter hinter) { - loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone); + loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone, hinter); } private void loadSubGlyph(int glyphIndex, @@ -131,7 +133,8 @@ final class GlyphLoader boolean antialias, Zone glyphZone, int preTranslateX, - int preTranslateY) + int preTranslateY, + Hinter hinter) { ByteBuffer glyph; int numContours; @@ -159,11 +162,11 @@ final class GlyphLoader if (numContours >= 0) loadSimpleGlyph(glyphIndex, pointSize, transform, antialias, numContours, glyph, glyphZone, - preTranslateX, preTranslateY); + preTranslateX, preTranslateY, hinter); else loadCompoundGlyph(glyphIndex, pointSize, transform, antialias, glyph, glyphZone, - preTranslateX, preTranslateY); + preTranslateX, preTranslateY, hinter); } @@ -172,7 +175,8 @@ final class GlyphLoader boolean antialias, int numContours, ByteBuffer glyph, Zone glyphZone, - int preTranslateX, int preTranslateY) + int preTranslateX, int preTranslateY, + Hinter hinter) { int numPoints; int posInstructions, numInstructions; @@ -203,10 +207,10 @@ final class GlyphLoader glyphZone.transform(pointSize, transform, unitsPerEm, preTranslateX, preTranslateY); - if (execInstructions) - { - // FIXME: Hint the glyph. - } + if (execInstructions && hinter != null) + { + hinter.applyHints(glyphZone); + } } @@ -229,7 +233,8 @@ final class GlyphLoader boolean antialias, ByteBuffer glyph, Zone glyphZone, - int preTranslateX, int preTranslateY) + int preTranslateX, int preTranslateY, + Hinter hinter) { short flags; int subGlyphIndex; @@ -326,7 +331,7 @@ final class GlyphLoader loadSubGlyph(subGlyphIndex, pointSize, componentTransform, antialias, subGlyphZone, Math.round((float) e + preTranslateX), - Math.round(-((float) f + preTranslateY))); + Math.round(-((float) f + preTranslateY)), hinter); glyphZone.combineWithSubGlyph(subGlyphZone, 4); glyph.limit(lim).position(pos); } diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java new file mode 100644 index 00000000000..c9664d2dc07 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java @@ -0,0 +1,285 @@ +/* Point.java -- Holds information for one point on a glyph outline + 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; + +/** + * Encapsulates information regarding one point on a glyph outline. + */ +public class Point +{ + public static final short FLAG_TOUCHED_X = 1; + public static final short FLAG_TOUCHED_Y = 2; + public static final short FLAG_ON_CURVE = 4; + public static final short FLAG_CONTOUR_END = 8; + public static final short FLAG_WEAK_INTERPOLATION = 16; + public static final short FLAG_INFLECTION = 32; + public static final short FLAG_DONE_X = 64; + public static final short FLAG_DONE_Y = 128; + + /** + * Right direction. + */ + public static final int DIR_RIGHT = 1; + + /** + * Left direction. + */ + public static final int DIR_LEFT = -1; + + /** + * Up direction. + */ + public static final int DIR_UP = 2; + + /** + * Down direction. + */ + public static final int DIR_DOWN = -2; + + /** + * The original x coordinate in font units. + */ + int origX; + + /** + * The original y coordinate in font units. + */ + int origY; + + /** + * The x coordinate scaled to the target. + */ + int scaledX; + + /** + * The y coordinate scaled to the target. + */ + int scaledY; + + /** + * The final hinted and scaled x coordinate. + */ + int x; + + /** + * The final hinted and scaled y coordinate. + */ + int y; + + int u; + int v; + + /** + * The glyph flags. + */ + short flags; + + /** + * The previous point in the contour. + */ + private Point prev; + + /** + * The next point in the contour. + */ + private Point next; + + /** + * The in-direction of the point, according to the DIR_* constants of this + * class. + */ + int inDir; + + /** + * The out-direction of the point, according to the DIR_* constants of this + * class. + */ + int outDir; + + public Point getNext() + { + return next; + } + + public void setNext(Point next) + { + this.next = next; + } + + public Point getPrev() + { + return prev; + } + + public void setPrev(Point prev) + { + this.prev = prev; + } + + public int getOrigX() + { + return origX; + } + + public void setOrigX(int origX) + { + this.origX = origX; + } + + public int getOrigY() + { + return origY; + } + + public void setOrigY(int origY) + { + this.origY = origY; + } + + public int getInDir() + { + return inDir; + } + + public void setInDir(int inDir) + { + this.inDir = inDir; + } + + public int getOutDir() + { + return outDir; + } + + public void setOutDir(int outDir) + { + this.outDir = outDir; + } + + public short getFlags() + { + return flags; + } + + public void setFlags(short flags) + { + this.flags = flags; + } + + public void addFlags(short flags) + { + this.flags |= flags; + } + + public boolean isControlPoint() + { + return (flags & FLAG_ON_CURVE) == 0; + } + + public int getU() + { + return u; + } + + public void setU(int u) + { + this.u = u; + } + + public int getV() + { + return v; + } + + public void setV(int v) + { + this.v = v; + } + + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[Point] origX: "); + s.append(origX); + s.append(", origY: "); + s.append(origY); + // TODO: Add more info when needed. + return s.toString(); + } + + public int getX() + { + return x; + } + + public void setX(int x) + { + this.x = x; + } + + public int getY() + { + return y; + } + + public void setY(int y) + { + this.y = y; + } + + public int getScaledX() + { + return scaledX; + } + + public void setScaledX(int scaledX) + { + this.scaledX = scaledX; + } + + public int getScaledY() + { + return scaledY; + } + + public void setScaledY(int scaledY) + { + this.scaledY = scaledY; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java index 8dfdeff0790..5f5cc0001d9 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java @@ -37,6 +37,7 @@ exception statement from your version. */ package gnu.java.awt.font.opentype.truetype; +import gnu.java.awt.font.opentype.Hinter; import gnu.java.awt.font.opentype.Scaler; import java.awt.FontFormatException; @@ -191,17 +192,18 @@ public final class TrueTypeScaler float pointSize, AffineTransform deviceTransform, boolean antialias, - boolean fractionalMetrics) + boolean fractionalMetrics, Hinter hinter, + int type) { glyphLoader.loadGlyph(glyphIndex, pointSize, deviceTransform, - antialias, glyphZone); - return glyphZone.getPath(); + antialias, glyphZone, hinter); + return glyphZone.getPath(type); } public Zone getRawOutline(int glyphIndex, AffineTransform transform) { Zone zone = new Zone(glyphZone.getCapacity()); - glyphLoader.loadGlyph(glyphIndex, transform, zone); + glyphLoader.loadGlyph(glyphIndex, transform, zone, null); return zone; } diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java index ff5bb631619..7c25a0a6a49 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java @@ -37,6 +37,8 @@ exception statement from your version. */ package gnu.java.awt.font.opentype.truetype; +import gnu.java.awt.font.FontDelegate; + import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; @@ -47,27 +49,19 @@ import java.awt.geom.PathIterator; */ public final class Zone { - private final int[] pos; - private final int[] origPos; - private final byte[] flags; + private Point[] points; 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 double scaleX, scaleY, shearX, shearY; public Zone(int maxNumPoints) { - origPos = new int[maxNumPoints * 2]; - pos = new int[maxNumPoints * 2]; - flags = new byte[maxNumPoints]; + points = new Point[maxNumPoints]; } - public int getCapacity() { - return flags.length; + return points.length; } @@ -79,91 +73,110 @@ public final class Zone public int getX(int point) { - return pos[2 * point]; + return getX(point, FontDelegate.FLAG_FITTED); + } + + public int getX(int point, int flags) + { + int x; + if ((flags & FontDelegate.FLAG_FITTED) != 0) + x = points[point].x; + else + x = points[point].scaledX; + return x; } public void setX(int point, int value, boolean touch) { - pos[2 * point] = value; + points[point].scaledX = value; + points[point].x = value; if (touch) - flags[point] |= FLAG_TOUCHED_X; + points[point].flags |= Point.FLAG_TOUCHED_X; } public void setY(int point, int value, boolean touch) { - pos[2 * point + 1] = value; + points[point].scaledY = value; + points[point].y = value; if (touch) - flags[point] |= FLAG_TOUCHED_Y; + points[point].flags |= Point.FLAG_TOUCHED_Y; } - public int getY(int point) { - return pos[2 * point + 1]; + return getY(point, FontDelegate.FLAG_FITTED); + } + + public int getY(int point, int flags) + { + int y; + if ((flags & FontDelegate.FLAG_FITTED) != 0) + y = points[point].y; + else + y = points[point].scaledY; + return y; } public int getOriginalX(int point) { - return origPos[2 * point]; + return points[point].origX; } public int getOriginalY(int point) { - return origPos[2 * point + 1]; + return points[point].origY; } public void setOriginalX(int point, int x) { - origPos[2 * point] = x; + points[point].origX = x; } public void setOriginalY(int point, int y) { - origPos[2 * point + 1] = y; + points[point].origY = 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; + points[i] = new Point(); + this.numPoints = numPoints; } public boolean isOnCurve(int point) { - return (flags[point] & FLAG_ON_CURVE) != 0; + return (points[point].flags & Point.FLAG_ON_CURVE) != 0; } public void setOnCurve(int point, boolean onCurve) { if (onCurve) - flags[point] |= FLAG_ON_CURVE; + points[point].flags |= Point.FLAG_ON_CURVE; else - flags[point] &= ~FLAG_ON_CURVE; + points[point].flags &= ~Point.FLAG_ON_CURVE; } public boolean isContourEnd(int point) { - return (flags[point] & FLAG_CONTOUR_END) != 0; + return (points[point].flags & Point.FLAG_CONTOUR_END) != 0; } public void setContourEnd(int point, boolean segEnd) { if (segEnd) - flags[point] |= FLAG_CONTOUR_END; + points[point].flags |= Point.FLAG_CONTOUR_END; else - flags[point] &= ~FLAG_CONTOUR_END; + points[point].flags &= ~Point.FLAG_CONTOUR_END; } @@ -172,7 +185,6 @@ public final class Zone void transform(double pointSize, AffineTransform deviceTransform, int unitsPerEm, int preTranslateX, int preTranslateY) { - double scaleX, scaleY, shearX, shearY; double factor; factor = pointSize / (double) unitsPerEm; @@ -183,11 +195,13 @@ public final class Zone for (int i = 0; i < numPoints; i++) { - int x = origPos[2 * i] + preTranslateX; - int y = origPos[2 * i + 1] + preTranslateY; + int x = points[i].origX + preTranslateX; + int y = points[i].origY + 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); + points[i].scaledX = points[i].x = Fixed.valueOf(scaleX * x + + shearX * y); + points[i].scaledY = points[i].y = Fixed.valueOf(shearY * x + + scaleY * y); } } @@ -197,11 +211,7 @@ public final class Zone { 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); + System.arraycopy(zone.points, 0, this.points, offset, count); this.numPoints += count - numPhantomPoints; } @@ -211,9 +221,9 @@ public final class Zone 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(Fixed.toString(points[i].scaledX, points[i].scaledY)); System.out.print(' '); - System.out.print(Fixed.toString(origPos[i*2], origPos[i*2+1])); + System.out.print(Fixed.toString(points[i].origX, points[i].origY)); System.out.print(' '); if (isOnCurve(i)) System.out.print('.'); @@ -228,16 +238,54 @@ public final class Zone } - public PathIterator getPathIterator() + public PathIterator getPathIterator(int type) { - return new ZonePathIterator(this); + return new ZonePathIterator(this, type); } - public GeneralPath getPath() + public GeneralPath getPath(int type) { GeneralPath p = new GeneralPath(GeneralPath.WIND_NON_ZERO, numPoints); - p.append(getPathIterator(), /* connect */ false); + p.append(getPathIterator(type), /* connect */ false); return p; } + + /** + * Returns the number of contours in this outline. + * + * @return the number of contours in this outline + */ + public int getNumContours() + { + int num = 0; + for (int i = 0; i < numPoints; i++) + { + if (isContourEnd(i)) + num++; + } + return num; + } + + public int getContourEnd(int n) + { + int idx = -1; + int num = 0; + for (int i = 0; i < numPoints; i++) + { + if (isContourEnd(i)) + { + idx = i; + if (num == n) + break; + num++; + } + } + return idx; + } + + public Point[] getPoints() + { + return points; + } } diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java index d000b9c3e42..0f60828b892 100644 --- a/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java @@ -116,6 +116,7 @@ final class ZonePathIterator private int contourStart; + private int type; /** * Constructs a ZonePathIterator for the specified zone. @@ -123,9 +124,10 @@ final class ZonePathIterator * @param zone the zone whose segments will be enumerated * by this iterator. */ - ZonePathIterator(Zone zone) + ZonePathIterator(Zone zone, int t) { this.zone = zone; + type = t; numPoints = zone.getSize() - /* four phantom points */ 4; // The first segment that needs to be emitted is a SEG_MOVETO. @@ -309,8 +311,8 @@ final class ZonePathIterator int curX, curY; int succ, succX, succY; - curX = zone.getX(cur); - curY = zone.getY(cur); + curX = zone.getX(cur, type); + curY = zone.getY(cur, type); coords[0] = Fixed.floatValue(curX); coords[1] = Fixed.floatValue(curY); @@ -318,8 +320,8 @@ final class ZonePathIterator return PathIterator.SEG_LINETO; succ = getSuccessor(cur); - succX = zone.getX(succ); - succY = zone.getY(succ); + succX = zone.getX(succ, type); + succY = zone.getY(succ, type); if (zone.isOnCurve(succ)) { @@ -359,8 +361,8 @@ final class ZonePathIterator if (zone.isOnCurve(contourStart)) { - x = zone.getX(contourStart); - y = zone.getY(contourStart); + x = zone.getX(contourStart, type); + y = zone.getY(contourStart, type); } else { @@ -374,13 +376,13 @@ final class ZonePathIterator /* 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); + x = zone.getX(contourEnd, type); + y = zone.getY(contourEnd, type); } else { - x = (zone.getX(contourStart) + zone.getX(contourEnd)) / 2; - y = (zone.getY(contourStart) + zone.getY(contourEnd)) / 2; + x = (zone.getX(contourStart, type) + zone.getX(contourEnd, type)) / 2; + y = (zone.getY(contourStart, type) + zone.getY(contourEnd, type)) / 2; } } diff --git a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java index da21253980f..f6c5ff0cb3b 100644 --- a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java +++ b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java @@ -67,8 +67,6 @@ import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.Line2D; import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; @@ -82,7 +80,6 @@ import java.awt.image.renderable.RenderableImage; import java.text.AttributedCharacterIterator; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; /** @@ -154,6 +151,11 @@ public abstract class AbstractGraphics2D { /** + * The default font to use on the graphics object. + */ + private static final Font FONT = new Font("SansSerif", Font.PLAIN, 12); + + /** * Accuracy of the sampling in the anti-aliasing shape filler. * Lower values give more speed, while higher values give more quality. * It is advisable to choose powers of two. @@ -164,7 +166,14 @@ public abstract class AbstractGraphics2D * Caches certain shapes to avoid massive creation of such Shapes in * the various draw* and fill* methods. */ - private static final ThreadLocal shapeCache = new ThreadLocal(); + private static final ThreadLocal<ShapeCache> shapeCache = + new ThreadLocal<ShapeCache>(); + + /** + * The scanline converters by thread. + */ + private static final ThreadLocal<ScanlineConverter> scanlineConverters = + new ThreadLocal<ScanlineConverter>(); /** * The transformation for this Graphics2D instance @@ -177,6 +186,11 @@ public abstract class AbstractGraphics2D private Paint paint; /** + * The paint context during rendering. + */ + private PaintContext paintContext; + + /** * The background. */ private Color background; @@ -239,6 +253,17 @@ public abstract class AbstractGraphics2D */ private boolean isOptimized = true; + private static final BasicStroke STANDARD_STROKE = new BasicStroke(); + + private static final HashMap STANDARD_HINTS; + static { + HashMap hints = new HashMap(); + hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_DEFAULT); + STANDARD_HINTS = hints; + } /** * Creates a new AbstractGraphics2D instance. */ @@ -247,13 +272,8 @@ public abstract class AbstractGraphics2D transform = new AffineTransform(); background = Color.WHITE; composite = AlphaComposite.SrcOver; - stroke = new BasicStroke(); - HashMap hints = new HashMap(); - hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); - hints.put(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_DEFAULT); - renderingHints = new RenderingHints(hints); + stroke = STANDARD_STROKE; + renderingHints = new RenderingHints(STANDARD_HINTS); } /** @@ -958,15 +978,8 @@ public abstract class AbstractGraphics2D */ public void drawGlyphVector(GlyphVector gv, float x, float y) { - int numGlyphs = gv.getNumGlyphs(); translate(x, y); - // TODO: We could use fill(gv.getOutline()), but that seems to be - // slightly more inefficient. - for (int i = 0; i < numGlyphs; i++) - { - Shape o = gv.getGlyphOutline(i); - fillShape(o, true); - } + fillShape(gv.getOutline(), true); translate(-x, -y); } @@ -1557,21 +1570,14 @@ public abstract class AbstractGraphics2D antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON); } - Rectangle2D userBounds = s.getBounds2D(); - Rectangle2D deviceBounds = new Rectangle2D.Double(); - ArrayList segs = getSegments(s, transform, deviceBounds, false); - Rectangle2D clipBounds = new Rectangle2D.Double(); - ArrayList clipSegs = getSegments(clip, transform, clipBounds, true); - segs.addAll(clipSegs); - Rectangle2D inclClipBounds = new Rectangle2D.Double(); - Rectangle2D.union(clipBounds, deviceBounds, inclClipBounds); - if (segs.size() > 0) + ScanlineConverter sc = getScanlineConverter(); + int resolution = 0; + if (antialias) { - if (antialias) - fillShapeAntialias(segs, deviceBounds, userBounds, inclClipBounds); - else - fillShapeImpl(segs, deviceBounds, userBounds, inclClipBounds); + // Adjust resolution according to rendering hints. + resolution = 2; } + sc.renderShape(this, s, clip, transform, resolution); } /** @@ -1705,141 +1711,6 @@ public abstract class AbstractGraphics2D } /** - * Fills the specified polygon without anti-aliasing. - */ - private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D, - Rectangle2D userBounds, - Rectangle2D inclClipBounds) - { - // This is an implementation of a polygon scanline conversion algorithm - // described here: - // http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/scan/ - - // Create table of all edges. - // The edge buckets, sorted and indexed by their Y values. - - double minX = deviceBounds2D.getMinX(); - double minY = deviceBounds2D.getMinY(); - double maxX = deviceBounds2D.getMaxX(); - double maxY = deviceBounds2D.getMaxY(); - double icMinY = inclClipBounds.getMinY(); - double icMaxY = inclClipBounds.getMaxY(); - Rectangle deviceBounds = new Rectangle((int) minX, (int) minY, - (int) Math.ceil(maxX) - (int) minX, - (int) Math.ceil(maxY) - (int) minY); - PaintContext pCtx = paint.createContext(getColorModel(), deviceBounds, - userBounds, transform, renderingHints); - - ArrayList[] edgeTable = new ArrayList[(int) Math.ceil(icMaxY) - - (int) Math.ceil(icMinY) + 1]; - - for (Iterator i = segs.iterator(); i.hasNext();) - { - PolyEdge edge = (PolyEdge) i.next(); - int yindex = (int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY); - if (edgeTable[yindex] == null) // Create bucket when needed. - edgeTable[yindex] = new ArrayList(); - edgeTable[yindex].add(edge); // Add edge to the bucket of its line. - } - - // TODO: The following could be useful for a future optimization. -// // Sort all the edges in the edge table within their buckets. -// for (int y = 0; y < edgeTable.length; y++) -// { -// if (edgeTable[y] != null) -// Collections.sort(edgeTable[y]); -// } - - // The activeEdges list contains all the edges of the current scanline - // ordered by their intersection points with this scanline. - ArrayList activeEdges = new ArrayList(); - PolyEdgeComparator comparator = new PolyEdgeComparator(); - - // Scan all relevant lines. - int minYInt = (int) Math.ceil(icMinY); - - Rectangle devClip = getDeviceBounds(); - int scanlineMax = (int) Math.min(maxY, devClip.getMaxY()); - for (int y = minYInt; y < scanlineMax; y++) - { - ArrayList bucket = edgeTable[y - minYInt]; - // Update all the x intersections in the current activeEdges table - // and remove entries that are no longer in the scanline. - for (Iterator i = activeEdges.iterator(); i.hasNext();) - { - PolyEdge edge = (PolyEdge) i.next(); - if (y > edge.y1) - i.remove(); - else - { - edge.xIntersection += edge.slope; - //edge.xIntersection = edge.x0 + edge.slope * (y - edge.y0); - //System.err.println("edge.xIntersection: " + edge.xIntersection); - } - } - - if (bucket != null) - activeEdges.addAll(bucket); - - // Sort current edges. We are using a bubble sort, because the order - // of the intersections will not change in most situations. They - // will only change, when edges intersect each other. - int size = activeEdges.size(); - if (size > 1) - { - for (int i = 1; i < size; i++) - { - PolyEdge e1 = (PolyEdge) activeEdges.get(i - 1); - PolyEdge e2 = (PolyEdge) activeEdges.get(i); - if (comparator.compare(e1, e2) > 0) - { - // Swap e2 with its left neighbor until it 'fits'. - int j = i; - do - { - activeEdges.set(j, e1); - activeEdges.set(j - 1, e2); - j--; - if (j >= 1) - e1 = (PolyEdge) activeEdges.get(j - 1); - } while (j >= 1 && comparator.compare(e1, e2) > 0); - } - } - } - - // Now draw all pixels inside the polygon. - // This is the last edge that intersected the scanline. - PolyEdge previous = null; // Gets initialized below. - boolean insideShape = false; - boolean insideClip = false; - //System.err.println("scanline: " + y); - for (Iterator i = activeEdges.iterator(); i.hasNext();) - { - PolyEdge edge = (PolyEdge) i.next(); - if (edge.y1 <= y) - continue; - - // Draw scanline when we are inside the shape AND inside the - // clip. - if (insideClip && insideShape) - { - int x0 = (int) previous.xIntersection; - int x1 = (int) edge.xIntersection; - if (x0 < x1) - fillScanline(pCtx, x0, x1, y); - } - // Update state. - previous = edge; - if (edge.isClip) - insideClip = ! insideClip; - else - insideShape = ! insideShape; - } - } - pCtx.dispose(); - } - - /** * Paints a scanline between x0 and x1. Override this when your backend * can efficiently draw/fill horizontal lines. * @@ -1847,8 +1718,9 @@ public abstract class AbstractGraphics2D * @param x1 the right offset * @param y the scanline */ - protected void fillScanline(PaintContext pCtx, int x0, int x1, int y) + protected void fillScanline(int x0, int x1, int y) { + PaintContext pCtx = paintContext; Raster paintRaster = pCtx.getRaster(x0, y, x1 - x0, 1); ColorModel paintColorModel = pCtx.getColorModel(); CompositeContext cCtx = composite.createContext(paintColorModel, @@ -1860,198 +1732,6 @@ public abstract class AbstractGraphics2D cCtx.dispose(); } - /** - * Fills arbitrary shapes in an anti-aliased fashion. - * - * @param segs the line segments which define the shape which is to be filled - */ - private void fillShapeAntialias(ArrayList segs, Rectangle2D deviceBounds2D, - Rectangle2D userBounds, - Rectangle2D inclClipBounds) - { - // This is an implementation of a polygon scanline conversion algorithm - // described here: - // http://www.cs.berkeley.edu/~ug/slide/pipeline/assignments/scan/ - // The antialiasing is implemented using a sampling technique, we do - // not scan whole lines but fractions of the line. - - double minX = deviceBounds2D.getMinX(); - double minY = deviceBounds2D.getMinY(); - double maxX = deviceBounds2D.getMaxX(); - double maxY = deviceBounds2D.getMaxY(); - double icMinY = inclClipBounds.getMinY(); - double icMaxY = inclClipBounds.getMaxY(); - double icMinX = inclClipBounds.getMinX(); - double icMaxX = inclClipBounds.getMaxX(); - Rectangle deviceBounds = new Rectangle((int) minX, (int) minY, - (int) Math.ceil(maxX) - (int) minX, - (int) Math.ceil(maxY) - (int) minY); - PaintContext pCtx = paint.createContext(ColorModel.getRGBdefault(), - deviceBounds, - userBounds, transform, - renderingHints); - - // This array will contain the oversampled transparency values for - // each pixel in the scanline. - int numScanlines = (int) Math.ceil(icMaxY) - (int) icMinY; - int numScanlinePixels = (int) Math.ceil(icMaxX) - (int) icMinX + 1; - if (alpha == null || alpha.length < (numScanlinePixels + 1)) - alpha = new int[numScanlinePixels + 1]; - - int firstLine = (int) icMinY; - //System.err.println("minY: " + minY); - int firstSubline = (int) (Math.ceil((icMinY - Math.floor(icMinY)) * AA_SAMPLING)); - double firstLineDouble = firstLine + firstSubline / (double) AA_SAMPLING; - //System.err.println("firstSubline: " + firstSubline); - - // Create table of all edges. - // The edge buckets, sorted and indexed by their Y values. - //System.err.println("numScanlines: " + numScanlines); - if (edgeTable == null - || edgeTable.length < numScanlines * AA_SAMPLING + AA_SAMPLING) - edgeTable = new ArrayList[numScanlines * AA_SAMPLING + AA_SAMPLING]; - - //System.err.println("firstLineDouble: " + firstLineDouble); - - for (Iterator i = segs.iterator(); i.hasNext();) - { - PolyEdge edge = (PolyEdge) i.next(); - int yindex = (int) (Math.ceil((edge.y0 - firstLineDouble) * AA_SAMPLING)); - //System.err.println("yindex: " + yindex + " for y0: " + edge.y0); - // Initialize edge's slope and initial xIntersection. - edge.slope = ((edge.x1 - edge.x0) / (edge.y1 - edge.y0)) / AA_SAMPLING; - if (edge.y0 == edge.y1) // Horizontal edge. - edge.xIntersection = Math.min(edge.x0, edge.x1); - else - { - double alignedFirst = Math.ceil(edge.y0 * AA_SAMPLING) / AA_SAMPLING; - edge.xIntersection = edge.x0 + (edge.slope * AA_SAMPLING) * (alignedFirst - edge.y0); - } - //System.err.println(edge); - // FIXME: Sanity check should not be needed when clipping works. - if (yindex >= 0 && yindex < edgeTable.length) - { - if (edgeTable[yindex] == null) // Create bucket when needed. - edgeTable[yindex] = new ArrayList(); - edgeTable[yindex].add(edge); // Add edge to the bucket of its line. - } - } - - // The activeEdges list contains all the edges of the current scanline - // ordered by their intersection points with this scanline. - ArrayList activeEdges = new ArrayList(); - PolyEdgeComparator comparator = new PolyEdgeComparator(); - - // Scan all lines. - int yindex = 0; - //System.err.println("firstLine: " + firstLine + ", maxY: " + maxY + ", firstSubline: " + firstSubline); - for (int y = firstLine; y <= icMaxY; y++) - { - int leftX = (int) icMaxX; - int rightX = (int) icMinX; - boolean emptyScanline = true; - for (int subY = firstSubline; subY < AA_SAMPLING; subY++) - { - //System.err.println("scanline: " + y + ", subScanline: " + subY); - ArrayList bucket = edgeTable[yindex]; - // Update all the x intersections in the current activeEdges table - // and remove entries that are no longer in the scanline. - for (Iterator i = activeEdges.iterator(); i.hasNext();) - { - PolyEdge edge = (PolyEdge) i.next(); - // TODO: Do the following using integer arithmetics. - if ((y + ((double) subY / (double) AA_SAMPLING)) > edge.y1) - i.remove(); - else - { - edge.xIntersection += edge.slope; - //System.err.println("edge: " + edge); - //edge.xIntersection = edge.x0 + edge.slope * (y - edge.y0); - //System.err.println("edge.xIntersection: " + edge.xIntersection); - } - } - - if (bucket != null) - { - activeEdges.addAll(bucket); - edgeTable[yindex].clear(); - } - - // Sort current edges. We are using a bubble sort, because the order - // of the intersections will not change in most situations. They - // will only change, when edges intersect each other. - int size = activeEdges.size(); - if (size > 1) - { - for (int i = 1; i < size; i++) - { - PolyEdge e1 = (PolyEdge) activeEdges.get(i - 1); - PolyEdge e2 = (PolyEdge) activeEdges.get(i); - if (comparator.compare(e1, e2) > 0) - { - // Swap e2 with its left neighbor until it 'fits'. - int j = i; - do - { - activeEdges.set(j, e1); - activeEdges.set(j - 1, e2); - j--; - if (j >= 1) - e1 = (PolyEdge) activeEdges.get(j - 1); - } while (j >= 1 && comparator.compare(e1, e2) > 0); - } - } - } - - // Now draw all pixels inside the polygon. - // This is the last edge that intersected the scanline. - PolyEdge previous = null; // Gets initialized below. - boolean insideClip = false; - boolean insideShape = false; - //System.err.println("scanline: " + y + ", subscanline: " + subY); - for (Iterator i = activeEdges.iterator(); i.hasNext();) - { - PolyEdge edge = (PolyEdge) i.next(); - if (edge.y1 <= (y + (subY / (double) AA_SAMPLING))) - continue; - - if (insideClip && insideShape) - { - // TODO: Use integer arithmetics here. - if (edge.y1 > (y + (subY / (double) AA_SAMPLING))) - { - //System.err.println(edge); - // TODO: Eliminate the aligments. - int x0 = (int) Math.min(Math.max(previous.xIntersection, minX), maxX); - int x1 = (int) Math.min(Math.max(edge.xIntersection, minX), maxX); - //System.err.println("minX: " + minX + ", x0: " + x0 + ", x1: " + x1 + ", maxX: " + maxX); - // TODO: Pull out cast. - int left = x0 - (int) minX; - int right = x1 - (int) minX + 1; - alpha[left]++; - alpha[right]--; - leftX = Math.min(x0, leftX); - rightX = Math.max(x1+2, rightX); - emptyScanline = false; - } - } - previous = edge; - if (edge.isClip) - insideClip = ! insideClip; - else - insideShape = ! insideShape; - } - yindex++; - } - firstSubline = 0; - // Render full scanline. - //System.err.println("scanline: " + y); - if (! emptyScanline) - fillScanlineAA(alpha, leftX, y, rightX - leftX, pCtx, (int) minX); - } - - pCtx.dispose(); - } /** * Fills a horizontal line between x0 and x1 for anti aliased rendering. @@ -2113,7 +1793,6 @@ public abstract class AbstractGraphics2D cCtx.dispose(); } - /** * Initializes this graphics object. This must be called by subclasses in * order to correctly initialize the state of this object. @@ -2121,13 +1800,8 @@ public abstract class AbstractGraphics2D protected void init() { setPaint(Color.BLACK); - setFont(new Font("SansSerif", Font.PLAIN, 12)); + setFont(FONT); isOptimized = true; - - // FIXME: Should not be necessary. A clip of null should mean - // 'clip against device bounds. - destinationRaster = getDestinationRaster(); - clip = getDeviceBounds(); } /** @@ -2267,91 +1941,33 @@ public abstract class AbstractGraphics2D } /** - * Converts the specified shape into a list of segments. - * - * @param s the shape to convert - * @param t the transformation to apply before converting - * @param deviceBounds an output parameter; holds the bounding rectangle of - * s in device space after return - * @param isClip true when the shape is a clip, false for normal shapes; - * this influences the settings in the created PolyEdge instances. + * Returns the ShapeCache for the calling thread. * - * @return a list of PolyEdge that form the shape in device space + * @return the ShapeCache for the calling thread */ - private ArrayList getSegments(Shape s, AffineTransform t, - Rectangle2D deviceBounds, boolean isClip) + private ShapeCache getShapeCache() { - // Flatten the path. TODO: Determine the best flattening factor - // wrt to speed and quality. - PathIterator path = s.getPathIterator(getTransform(), 1.0); - - // Build up polygons and let the native backend render this using - // rawFillShape() which would provide a default implementation for - // drawPixel using a PolyScan algorithm. - double[] seg = new double[6]; - - // TODO: Use ArrayList<PolyEdge> here when availble. - ArrayList segs = new ArrayList(); - double segX = 0.; // The start point of the current edge. - double segY = 0.; - double polyX = 0.; // The start point of the current polygon. - double polyY = 0.; - - double minX = Integer.MAX_VALUE; - double maxX = Integer.MIN_VALUE; - double minY = Integer.MAX_VALUE; - double maxY = Integer.MIN_VALUE; - - //System.err.println("fill polygon"); - while (! path.isDone()) + ShapeCache sc = shapeCache.get(); + if (sc == null) { - int segType = path.currentSegment(seg); - minX = Math.min(minX, seg[0]); - maxX = Math.max(maxX, seg[0]); - minY = Math.min(minY, seg[1]); - maxY = Math.max(maxY, seg[1]); - - //System.err.println("segment: " + segType + ", " + seg[0] + ", " + seg[1]); - if (segType == PathIterator.SEG_MOVETO) - { - segX = seg[0]; - segY = seg[1]; - polyX = seg[0]; - polyY = seg[1]; - } - else if (segType == PathIterator.SEG_CLOSE) - { - // Close the polyline. - PolyEdge edge = new PolyEdge(segX, segY, - polyX, polyY, isClip); - segs.add(edge); - } - else if (segType == PathIterator.SEG_LINETO) - { - PolyEdge edge = new PolyEdge(segX, segY, - seg[0], seg[1], isClip); - segs.add(edge); - segX = seg[0]; - segY = seg[1]; - } - path.next(); + sc = new ShapeCache(); + shapeCache.set(sc); } - deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY); - return segs; + return sc; } /** - * Returns the ShapeCache for the calling thread. + * Returns the scanline converter for this thread. * - * @return the ShapeCache for the calling thread + * @return the scanline converter for this thread */ - private ShapeCache getShapeCache() + private ScanlineConverter getScanlineConverter() { - ShapeCache sc = (ShapeCache) shapeCache.get(); + ScanlineConverter sc = scanlineConverters.get(); if (sc == null) { - sc = new ShapeCache(); - shapeCache.set(sc); + sc = new ScanlineConverter(); + scanlineConverters.set(sc); } return sc; } diff --git a/libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java b/libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java new file mode 100644 index 00000000000..4d1e777ccf5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java @@ -0,0 +1,195 @@ +/* ActiveEdges.java -- A collection of active edges for scanline conversion + 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; + +/** + * A collection of active edges for scanline conversion. + */ +final class ActiveEdges +{ + + /** + * The active edges. This can contain null values at arbirary locations. + * The method #sort() packs this together. + */ + private PolyEdge[] activeEdges; + + /** + * The actual number of active edges. The array can be bigger than this + * number. + */ + private int numActiveEdges; + + /** + * Creates a new ActiveEdges object. + */ + ActiveEdges() + { + activeEdges = new PolyEdge[8]; + numActiveEdges = 0; + } + + /** + * Clears out all active edges. This is cheap as it simply resets the + * counter to 0. It does not release all references to PolyEdge instances. + */ + void clear() + { + numActiveEdges = 0; + } + + /** + * Adds the specified edge to the list of active edges. This does not yet + * sort the edges and therefore does destroy any order of the list. + * + * @param edge the edge to add + */ + void add(PolyEdge edge) + { + // Grow array when necessary. + int oldSize = activeEdges.length; + if (numActiveEdges >= oldSize) + { + int newSize = oldSize + oldSize / 4 + 1; + PolyEdge[] newEdges = new PolyEdge[newSize]; + System.arraycopy(activeEdges, 0, newEdges, 0, oldSize); + activeEdges = newEdges; + } + activeEdges[numActiveEdges] = edge; + numActiveEdges++; + } + + /** + * Intersects all active edges, sorts them according to their intersection + * points and packs the array to remove unneeded edges. This does also + * remove any edges that do not intersect the scanline (i.e. they end above + * of the scanline). + * + * @param y the scanline height + */ + void intersectSortAndPack(int n, int y) + { + // Intersect and pack in one go. + int last = 0; + PolyEdge tmp; + for (int i = 0; i < numActiveEdges; i++) + { + PolyEdge edge = activeEdges[i]; + // Clear out edge that ends above the scanline. + if (edge != null && edge.y1 >= y) + { + assert edge.y1 >= y && edge.y0 <= y : "edge must cross scanline"; + edge.intersect(n, y); + activeEdges[last] = edge; + last++; + + // Bubble up the added edge. + for (int j = last - 1; j > 0; j--) + { + if (activeEdges[j].xIntersection + < activeEdges[j - 1].xIntersection) + { + tmp = activeEdges[j]; + activeEdges[j] = activeEdges[j - 1]; + activeEdges[j - 1] = tmp; + } + else + { + // The beginning of the list is already sorted. + break; + } + } + } + } + numActiveEdges = last; + + } + + /** + * Returns the number of active edges. This is only reliable after a + * call to {@link #intersectSortAndPack(int, int)}. + * + * @return the number of active edges + */ + int getNumActiveEdges() + { + return numActiveEdges; + } + + /** + * Returns the active edge at the position <code>i</code>. + * + * @param i the index + * + * @return the active edge at the specified index + */ + PolyEdge getActiveEdge(int i) + { + return activeEdges[i]; + } + + /** + * Removes all edges that end above the specified height. + * + * @param y the cut-off height + */ + void remove(int y) + { + for (int i = 0; i < numActiveEdges; i++) + { + PolyEdge edge = activeEdges[i]; + if (edge != null && edge.y1 < y) + { + activeEdges[i] = null; + } + } + } + + public String toString() + { + StringBuilder s = new StringBuilder(); + s.append("[ActiveEdges] "); + for (int i = 0; i < numActiveEdges; i++) + { + s.append(activeEdges[i]); + s.append(','); + } + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java b/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java index 6c3b546881a..eb0cc7f8f3e 100644 --- a/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java +++ b/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java @@ -38,31 +38,38 @@ exception statement from your version. */ package gnu.java.awt.java2d; +import gnu.java.math.Fixed; + /** - * An edge in a polygon. This is used by the scanline conversion algorithm - * implemented in {@link AbstractGraphics2D#rawFillShape}. + * An edge in a polygon. * * @author Roman Kennke (kennke@aicas.com) */ -public class PolyEdge +final class PolyEdge implements Comparable { /** * The start and end coordinates of the edge. y0 is always smaller or equal * than y1. + * + * These values are stored as fixed-point decimals. */ - public double x0, y0, x1, y1; + public int x0, y0, x1, y1; /** * The slope of the edge. This is dx / dy. + * + * This is a fixed point decimal. */ - double slope; + private int slope; /** * The intersection of this edge with the current scanline. + * + * This is a fixed point decimal. */ - double xIntersection; + int xIntersection; /** * Indicates whether this edge is from the clip or from the target shape. @@ -70,6 +77,24 @@ public class PolyEdge boolean isClip; /** + * Implements a linked list for the edge pool. + */ + PolyEdge poolNext; + + /** + * Implements a linked list for the scanline edge lists. + */ + PolyEdge scanlineNext; + + /** + * Create an uninitialized edge. + */ + PolyEdge() + { + // Nothing to do here. + } + + /** * Creates a new PolyEdge with the specified coordinates. * * @param x0 the starting point, x coordinate @@ -77,7 +102,20 @@ public class PolyEdge * @param x1 the end point, x coordinate * @param y1 the end point, y coordinate */ - PolyEdge(double x0, double y0, double x1, double y1, boolean clip) + PolyEdge(int n, int x0, int y0, int x1, int y1, boolean clip) + { + init(n, x0, y0, x1, y1, clip); + } + + /** + * (Re-) Initializes this edge. + * + * @param x0 + * @param y0 + * @param x1 + * @param y1 + */ + void init(int n, int x0, int y0, int x1, int y1, boolean clip) { isClip = clip; if (y0 < y1) @@ -94,11 +132,7 @@ public class PolyEdge 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); + slope = Fixed.div(n, this.x1 - this.x0, this.y1 - this.y0); } /** @@ -115,6 +149,19 @@ public class PolyEdge return comp; } + /** + * Intersects this edge with the scanline at height y. The result is + * stored in {@link #xIntersection}. + * + * @param y the scanline + */ + void intersect(int n, int y) + { + int dy = y - y0; + int dx = Fixed.mul(n, slope, dy); + xIntersection = x0 + dx; + } + public String toString() { return "Edge: " + x0 + ", " + y0 + ", " + x1 + ", " + y1 + ", slope: " diff --git a/libjava/classpath/gnu/java/awt/java2d/Scanline.java b/libjava/classpath/gnu/java/awt/java2d/Scanline.java new file mode 100644 index 00000000000..24c3d34d5c3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/Scanline.java @@ -0,0 +1,91 @@ +/* Scanline.java -- A scanline for the scanline converter + 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; + +/** + * Represents a scanline in the {@link ScanlineConverter}. This is basically + * a sorted list of {@link PolyEdge}s that is made for maximum reuse. + */ +class Scanline +{ + + /** + * The actual edges array. The fields can be null. + */ + private PolyEdge edges; + + /** + * Clears this scanline. This only resets the number of edges to 0. The + * actual PolyEdge objects are preserved for possible later reuse. + */ + void clear() + { + edges = null; + } + + /** + * Create a new Scanline. + */ + Scanline() + { + // Nothing to do. + } + + /** + * Inserts an edge into this scanline. This is performed in a sorted fashion, + * and so that it reuses as much existing resources as possible. + */ + void addEdge(PolyEdge edge) + { + + // Allocate PolyEdge when necessary or reuse an old one. + edge.scanlineNext = edges; + edges = edge; + } + + /** + * Returns the edges queue. + * + * @return the edges queue + */ + PolyEdge getEdges() + { + return edges; + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java b/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java new file mode 100644 index 00000000000..9f9d8921f59 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java @@ -0,0 +1,404 @@ +/* ScanlineConverter.java -- Rasterizes Shapes + 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 gnu.java.math.Fixed; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; + +/** + * Rasterizes {@link Shape} objects on an AbstractGraphics2D. + */ +final class ScanlineConverter +{ + + /** + * The number of digits to use for fixed point arithmetics. + */ + private static int FIXED_DIGITS = 6; + + /** + * The fixed value for the number 1. + */ + private static int ONE = Fixed.fixedValue(FIXED_DIGITS, 1); + + /** + * The actual number of scanlines. + */ + private int numScanlines; + + /** + * The number of scanlines. This can contain more elements than we have + * scanlines. The real number of scanlines is stored in + * {@link #numScanlines}. This can also contain null values for empty + * scanlines. + */ + private Scanline[] scanlines; + + /** + * The upper bounds which correspond to the index 0 in the scanline array. + * + * This is a fixed point value. + */ + private int upperBounds; + + /** + * The resolution of the scanline converter. + * + * This is a fixed point value. + */ + private int resolution; + + /** + * One half step according to the resolution. This is stored to avoid + * unnecessary operations during rendering. + */ + private int halfStep; + + /** + * This is used in {@link #addShape(PathIterator, boolean)} to + * receive the coordinates of the path. + */ + private float[] coords; + + /** + * The active edges. + */ + private ActiveEdges activeEdges; + + private PolyEdge edgePool; + private PolyEdge edgePoolLast; + + private int minY; + private int maxY; + + /** + * Create a new ScanlineConverter. + */ + ScanlineConverter() + { + scanlines = new Scanline[10]; + coords = new float[6]; + activeEdges = new ActiveEdges(); + edgePool = new PolyEdge(); + edgePoolLast = edgePool; + } + + /** + * Renders the specified shape using the specified clip and transform. + * + * @param shape the shape to render + * @param clip the clip + * @param trans the transform + */ + void renderShape(AbstractGraphics2D g, Shape shape, Shape clip, + AffineTransform trans, int res) + { + // Prepare resolution and upper bounds. + clear(); + setResolution(res); + + boolean haveClip = clip != null; + + // Add shapes. + PathIterator path = shape.getPathIterator(trans, resolution); + addShape(path, false); + if (haveClip) + { + path= clip.getPathIterator(trans, resolution); + addShape(path, true); + } + + setUpperBounds(minY); + + PolyEdge edge = edgePool; + while (edge != edgePoolLast) + { + addEdge(edge); + edge = edge.poolNext; + } + + int y = upperBounds; + int lastIndex = scanlineIndex(y - resolution); + int index; + activeEdges.clear(); + // The render loop... + Scanline scanline = null; + while (y <= maxY) + { + // First we put together our list of active edges. + index = scanlineIndex(y); + // If we go outside the scanline array we still need to render the + // remaining edges until they end. + scanline = index < scanlines.length ? scanlines[index] : null; + if (scanline != null) + { + edge = scanline.getEdges(); + while (edge != null) + { + activeEdges.add(edge); + edge = edge.scanlineNext; + } + } + + // Then we intersect all active edges with the current scanline + // and sort them according to their intersection points. + activeEdges.intersectSortAndPack(FIXED_DIGITS, y + halfStep); + + // Ok, now we can perform the actual scanlining. + boolean push = lastIndex != index; + doScanline(g, y, push, haveClip); + + // Remove obsolete active edges. + //activeEdges.remove(y + halfStep); + + // Go on with the next line... + y += resolution; + lastIndex = index; + } + } + + /** + * Clears all scanlines. + */ + private void clear() + { + // Reset edge pool. + edgePoolLast = edgePool; + + // Reset scanlines. + for (int i = scanlines.length - 1; i >= 0 ; i--) + { + Scanline sl = scanlines[i]; + if (sl != null) + sl.clear(); + } + + // Reset bounds. + minY = Integer.MAX_VALUE; + maxY = Integer.MIN_VALUE; + } + + /** + * Performs the scanlining on the current set of active edges. + */ + private void doScanline(AbstractGraphics2D g, int y, boolean push, + boolean haveClip) + { + // We begin outside the clip and outside the shape. We only draw when + // we are inside the clip AND inside the shape. + boolean inClip = ! haveClip; + boolean inShape = false; + PolyEdge lastEdge = null; + int numEdges = activeEdges.getNumActiveEdges(); + for (int i = 0; i < numEdges; i++) + { + PolyEdge edge = activeEdges.getActiveEdge(i); + if (inClip && inShape) + { + assert lastEdge != null; + int x0 = lastEdge.xIntersection; + int x1 = edge.xIntersection; + assert x0 <= x1; + if (push) + { + if (resolution == ONE) + { + // Non-AA rendering. + g.fillScanline(Fixed.intValue(FIXED_DIGITS, x0), + Fixed.intValue(FIXED_DIGITS, x1 - resolution), + Fixed.intValue(FIXED_DIGITS, y)); + } + else + { + // AA rendering. + // FIXME: Implement. + System.err.println("Implement AA rendering."); + } + } + } + if (edge.isClip) + inClip = ! inClip; + else + inShape = ! inShape; + + lastEdge = edge; + } + } + + /** + * Sets the resolution. A value of 0 rasterizes the shape normally without + * anti-aliasing. Greater values renders with a resolution of 2 ^ res. + * + * @param res the resolution + */ + private void setResolution(int res) + { + int one = Fixed.fixedValue(FIXED_DIGITS, 1); + resolution = one / (1 << res); + halfStep = resolution / 2; + } + + /** + * Sets the vertical bounds of that shape that is beeing rendered. + * + * @param y0 the upper bounds + */ + private void setUpperBounds(int y0) + { + upperBounds = fit(y0); + } + + /** + * Add a shape to the scanline converter. + * + * @param path + * @param clip + */ + private void addShape(PathIterator path, boolean clip) + { + int startX = 0; + int startY = 0; + int lastX = 0; + int lastY = 0; + while (! path.isDone()) + { + int type = path.currentSegment(coords); + switch (type) + { + case PathIterator.SEG_MOVETO: + startX = lastX = Fixed.fixedValue(FIXED_DIGITS, coords[0]); + startY = lastY = Fixed.fixedValue(FIXED_DIGITS, coords[1]); + minY = Math.min(startY, minY); + maxY = Math.max(startY, maxY); + break; + case PathIterator.SEG_LINETO: + int x = Fixed.fixedValue(FIXED_DIGITS, coords[0]); + int y = Fixed.fixedValue(FIXED_DIGITS, coords[1]); + edgePoolAdd(lastX, lastY, x, y, clip); + lastX = x; + lastY = y; + minY = Math.min(lastY, minY); + maxY = Math.max(lastY, maxY); + break; + case PathIterator.SEG_CLOSE: + edgePoolAdd(lastX, lastY, startX, startY, clip); + lastX = startX; + lastY = startY; + break; + case PathIterator.SEG_CUBICTO: + case PathIterator.SEG_QUADTO: + default: + assert false; + } + path.next(); + } + } + + /** + * Adds an edge into the scanline array. + */ + private void addEdge(PolyEdge edge) + { + // Determine index. + int upper = Math.min(edge.y0, edge.y1); + // Fit to raster. + int index = scanlineIndex(upper); + // Grow array when necessary. + if (index >= scanlines.length) + { + int oldSize = scanlines.length; + int newSize = Math.max(oldSize + oldSize / 2 + 1, index + 10); + Scanline[] newScanlines = new Scanline[newSize]; + System.arraycopy(scanlines, 0, newScanlines, 0, oldSize); + scanlines = newScanlines; + } + + // Add edge. + if (scanlines[index] == null) + { + scanlines[index] = new Scanline(); + } + scanlines[index].addEdge(edge); + } + + /** + * Fits an Y coordinate to the grid. + * + * @param y the Y coordinate to fit + * + * @return the fitted Y coordinate + */ + private int fit(int y) + { + int val1 = Fixed.div(FIXED_DIGITS, y, resolution); + int rounded = Fixed.round(FIXED_DIGITS, val1); + return Fixed.div(FIXED_DIGITS, rounded, resolution); + } + + /** + * Calculates the scanline index for the specified y coordinate. + * + * @param y the y coordinate as fixed point value + * + * @return the scanline index + */ + private int scanlineIndex(int y) + { + int fitted = fit(y); + // Cleverly skip the fixed point conversions here. + return (fitted - upperBounds)/ resolution; + } + + private void edgePoolAdd(int x0, int y0, int x1, int y1, boolean clip) + { + // Don't need no horizontal edges. + if (y0 != y1) + { + edgePoolLast.init(FIXED_DIGITS, x0, y0, x1, y1, clip); + if (edgePoolLast.poolNext == null) + { + edgePoolLast.poolNext = new PolyEdge(); + } + edgePoolLast = edgePoolLast.poolNext; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java new file mode 100644 index 00000000000..bef42dcea34 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java @@ -0,0 +1,301 @@ +/* ClasspathDesktopPeer.java -- Offers a concrete implementation for DesktopPeer + Copyright (C) 2006, 2007 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; + +import java.awt.AWTPermission; +import java.awt.Desktop.Action; +import java.awt.peer.DesktopPeer; + +import java.io.File; +import java.io.IOException; + +import java.net.URI; + +import java.util.prefs.Preferences; + +/** + * Offers a common implementation for the Desktop peers, that enables + * access to default system application within java processes. + * + * @author Mario Torre <neugens@limasoftware.net> + */ +public class ClasspathDesktopPeer + implements DesktopPeer +{ + /** This is the fallback browser, if no desktop was detected. */ + protected static final String _DEFAULT_BROWSER = "firefox"; + + /** gnu.java.awt.peer.Desktop.html.command */ + protected static final String _BROWSE = "html"; + + /** gnu.java.awt.peer.Desktop.mail.command */ + protected static final String _MAIL = "mail"; + + /** gnu.java.awt.peer.Desktop.edit.command */ + protected static final String _EDIT = "edit"; + + /** gnu.java.awt.peer.Desktop.print.command */ + protected static final String _PRINT = "print"; + + /** gnu.java.awt.peer.Desktop.open.command */ + protected static final String _OPEN = "open"; + + /** */ + protected static final KDEDesktopPeer kde = new KDEDesktopPeer(); + + /** */ + protected static final GnomeDesktopPeer gnome = new GnomeDesktopPeer(); + + /** */ + protected static final ClasspathDesktopPeer classpath = + new ClasspathDesktopPeer(); + + /** + * Preference subsystem. Packagers and users can override the default + * behaviour of this class via preferences and system properties. + */ + protected Preferences prefs = + Preferences.userNodeForPackage(ClasspathDesktopPeer.class).node("Desktop"); + + /** + * @param target + */ + protected ClasspathDesktopPeer() + { + /* nothing to do */ + } + + public boolean isSupported(Action action) + { + String check = null; + + switch(action) + { + case BROWSE: + check = _BROWSE; + break; + + case MAIL: + check = _MAIL; + break; + + case EDIT: + check = _EDIT; + break; + + case PRINT: + check = _PRINT; + break; + + case OPEN: default: + check = _OPEN; + break; + } + + return this.supportCommand(check); + } + + public void browse(URI url) throws IOException + { + checkPermissions(); + + String browser = getCommand(_BROWSE); + + if (browser == null) + throw new UnsupportedOperationException(); + + browser = browser + " " + url.toString(); + + Runtime.getRuntime().exec(browser); + } + + public void edit(File file) throws IOException + { + checkPermissions(file, false); + + String edit = getCommand(_EDIT); + + if (edit == null) + throw new UnsupportedOperationException(); + + edit = edit + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(edit); + } + + public void mail(URI mailtoURL) throws IOException + { + checkPermissions(); + + String scheme = mailtoURL.getScheme(); + if (scheme == null || !scheme.equalsIgnoreCase("mailto")) + throw new IllegalArgumentException("URI Scheme not of type mailto"); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + mail = mail + " " + mailtoURL.toString(); + + Runtime.getRuntime().exec(mail); + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail); + } + + public void open(File file) throws IOException + { + checkPermissions(file, true); + + String open = getCommand(_OPEN); + + if (open == null) + throw new UnsupportedOperationException(); + + open = open + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(open); + } + + public void print(File file) throws IOException + { + checkPrintPermissions(file); + + String print = getCommand(_PRINT); + + if (print == null) + throw new UnsupportedOperationException(); + + print = print + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(print); + } + + protected String getCommand(String action) + { + // check if a system property exist + String command = + System.getProperty("gnu.java.awt.peer.Desktop." + action + ".command"); + + // otherwise, get it from preferences, if any + if (command == null) + { + command = prefs.node(action).get("command", null); + } + + return command; + } + + /** + * Note: Checks for AWTPermission("showWindowWithoutWarningBanner") only. + */ + protected void checkPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new AWTPermission("showWindowWithoutWarningBanner")); + } + } + + /** + * Calls checkPermissions() and checks for SecurityManager.checkRead() + * and, if readOnly is false, for SecurityManager.checkWrite() + */ + protected void checkPermissions(File file, boolean readOnly) + { + checkPermissions(); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkRead(file.toString()); + if (!readOnly) sm.checkWrite(file.toString()); + } + } + + /** + * Calls checkPermissions(file, true) and checks for + * SecurityManager.checkPrintJobAccess() + */ + protected void checkPrintPermissions(File file) + { + checkPermissions(file, true); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPrintJobAccess(); + } + } + + /** + * @param check + * @return + */ + protected boolean supportCommand(String check) + { + return ((this.getCommand(check) != null) ? true : false); + } + + /** + * @return + */ + public static DesktopPeer getDesktop() + { + // check if we are under Gnome or KDE or anything else + String desktopSession = System.getenv("GNOME_DESKTOP_SESSION_ID"); + if (desktopSession == null) + { + desktopSession = System.getenv("KDE_FULL_SESSION"); + if (desktopSession != null) + return kde; + } + else + { + return gnome; + } + + // revert to this class for default values + return classpath; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java index 2176f34a5f1..60fde2557ac 100644 --- a/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java @@ -54,6 +54,7 @@ import java.awt.peer.FontPeer; import java.text.AttributedCharacterIterator; import java.text.CharacterIterator; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; @@ -120,6 +121,23 @@ public abstract class ClasspathFontPeer */ protected AffineTransform transform; + static class LRUCache<K,V> extends LinkedHashMap<K,V> + { + int max_entries; + public LRUCache(int max) + { + super(max, 0.75f, true); + max_entries = max; + } + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > max_entries; + } + } + + private static LRUCache<AffineTransform,TransformAttribute> transCache = + new LRUCache<AffineTransform,TransformAttribute>(50); + protected static ClasspathToolkit tk() { return (ClasspathToolkit)(Toolkit.getDefaultToolkit ()); @@ -200,7 +218,19 @@ public abstract class ClasspathFontPeer protected static void copyTransformToAttrs (AffineTransform trans, Map attrs) { if (trans != null) - attrs.put(TextAttribute.TRANSFORM, new TransformAttribute (trans)); + { + TransformAttribute ta; + synchronized(transCache) + { + ta = transCache.get(trans); + if (ta == null) + { + ta = new TransformAttribute(trans); + transCache.put(trans, ta); + } + } + attrs.put(TextAttribute.TRANSFORM, ta); + } } diff --git a/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java new file mode 100644 index 00000000000..be216318140 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java @@ -0,0 +1,153 @@ +/* GnomeDesktopPeer.java -- Offers a GNOME Desktop peer for DesktopPeer + Copyright (C) 2006, 2007 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; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +/** + * @author Mario Torre <neugens@limasoftware.net> + */ +public class GnomeDesktopPeer + extends ClasspathDesktopPeer +{ + /** + * Query string to use if a GNOME desktop is detected to get the name of the + * default browser. This requires gconftool-2 (part of GNOME). + */ + private static final String BROWSER_QUERY_GNOME = + "gconftool-2 -g /desktop/gnome/url-handlers/http/command"; + + protected String getCommand(String action) + { + // check if a command already exists + String command = super.getCommand(action); + + if (command == null) + { + try + { + if (action == _BROWSE) + { + command = execQuery(BROWSER_QUERY_GNOME); + } + else if (action == _PRINT) + { + command = null; + } + else + { + command = "gnome-open"; + } + } + catch (Exception e) + { + command = null; + } + } + + return command; + } + + public void browse(URI url) throws IOException + { + checkPermissions(); + + String browser = getCommand(_BROWSE); + + if (browser == null) + throw new UnsupportedOperationException(); + + browser = browser + " " + url.toString(); + + Runtime.getRuntime().exec(browser); + } + + protected boolean supportCommand(String check) + { + if (check == _PRINT) + { + return super.supportCommand(check); + } + + return true; + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail + " mailto:"); + } + + protected String execQuery(String command) throws IOException + { + InputStream in = null; + StringBuilder output = new StringBuilder(); + + try + { + Process process = Runtime.getRuntime().exec(command); + + // Get the input stream and read from it + in = process.getInputStream(); + int c; + while ((c = in.read()) != - 1) + { + output.append((char) c); + } + } + finally + { + if (in != null) + in.close(); + } + + // remove %s from the string, leave only the command line + int index = output.indexOf("%s"); + output.delete(index, index + 1); + + return output.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java new file mode 100644 index 00000000000..676bd891758 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java @@ -0,0 +1,135 @@ +/* GnomeDesktopPeer.java -- Offers a KDE Desktop peer for DesktopPeer + Copyright (C) 2006, 2007 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; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +/** + * @author Mario Torre <neugens@limasoftware.net> + */ +public class KDEDesktopPeer + extends ClasspathDesktopPeer +{ + /** + * Query string to use if a GNOME desktop is detected to get the name of the + * default browser. This requires gconftool-2 (part of GNOME). + */ + private static final String BROWSER_QUERY_GNOME = + "gconftool-2 -g /desktop/gnome/url-handlers/http/command"; + + protected String getCommand(String action) + { + // check if a command already exists + String command = super.getCommand(action); + + if (command == null) + { + try + { + if (action == _MAIL) + { + command = "kfmclient exec"; + } + else if (action == _PRINT) + { + command = "kprinter"; + } + else + { + command = "kfmclient openURL"; + } + } + catch (Exception e) + { + command = null; + } + } + + return command; + } + + protected boolean supportCommand(String check) + { + return true; + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail + " 'mailto: '"); + } + + protected String execQuery(String command) throws IOException + { + InputStream in = null; + StringBuilder output = new StringBuilder(); + + try + { + Process process = Runtime.getRuntime().exec(command); + + // Get the input stream and read from it + in = process.getInputStream(); + int c; + while ((c = in.read()) != - 1) + { + output.append((char) c); + } + } + finally + { + if (in != null) + in.close(); + } + + // remove %s from the string, leave only the command line + int index = output.indexOf("%s"); + output.delete(index, index + 1); + + return output.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java index 5238bfe7410..dad537aa748 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java @@ -61,11 +61,11 @@ public class AsyncImage private class NullImageSource implements ImageProducer { - private ArrayList consumers; + private ArrayList<ImageConsumer> consumers; NullImageSource() { - consumers = new ArrayList(); + consumers = new ArrayList<ImageConsumer>(); } public void addConsumer(ImageConsumer ic) @@ -145,14 +145,14 @@ public class AsyncImage * * This is package private to avoid accessor methods. */ - HashSet observers; + HashSet<ImageObserver> observers; /** * Creates a new AsyncImage that loads from the specified URL. */ AsyncImage(URL url) { - observers = new HashSet(); + observers = new HashSet<ImageObserver>(); Loader l = new Loader(url); Thread t = new Thread(l); t.start(); @@ -221,7 +221,7 @@ public class AsyncImage { // This field gets null when image loading is complete and we don't // need to store any more observers. - HashSet observs = observers; + HashSet<ImageObserver> observs = observers; if (observs != null) { observs.add(obs); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java index c792645d3e8..31c5e641ec8 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java @@ -40,6 +40,7 @@ package gnu.java.awt.peer.gtk; import java.awt.AlphaComposite; import java.awt.Color; +import java.awt.Composite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; @@ -49,7 +50,6 @@ import java.awt.Shape; import java.awt.Toolkit; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; @@ -75,12 +75,6 @@ public class BufferedImageGraphics extends CairoGraphics2D private BufferedImage image, buffer; /** - * Allows us to lock the image from updates (if we want to perform a few - * intermediary operations on the cairo surface, then update it all at once) - */ - private boolean locked; - - /** * Image size. */ private int imageWidth, imageHeight; @@ -93,7 +87,8 @@ public class BufferedImageGraphics extends CairoGraphics2D /** * Cache BufferedImageGraphics surfaces. */ - static WeakHashMap bufferedImages = new WeakHashMap(); + static WeakHashMap<BufferedImage, CairoSurface> bufferedImages + = new WeakHashMap<BufferedImage, CairoSurface>(); /** * Its corresponding cairo_t. @@ -109,30 +104,30 @@ public class BufferedImageGraphics extends CairoGraphics2D this.image = bi; imageWidth = bi.getWidth(); imageHeight = bi.getHeight(); - locked = false; if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel)) hasFastCM = false; else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque)) { - hasFastCM = true; - hasAlpha = false; + hasFastCM = true; + hasAlpha = false; } - else if(bi.getColorModel().equals(CairoSurface.cairoColorModel)) + else if(bi.getColorModel().equals(CairoSurface.cairoColorModel) + || bi.getColorModel().equals(CairoSurface.cairoCM_pre)) { - hasFastCM = true; - hasAlpha = true; + hasFastCM = true; + hasAlpha = true; } else hasFastCM = false; // Cache surfaces. if( bufferedImages.get( bi ) != null ) - surface = (CairoSurface)bufferedImages.get( bi ); + surface = bufferedImages.get( bi ); else { - surface = new CairoSurface( imageWidth, imageHeight ); - bufferedImages.put(bi, surface); + surface = new CairoSurface( imageWidth, imageHeight ); + bufferedImages.put(bi, surface); } cairo_t = surface.newCairoContext(); @@ -148,10 +143,7 @@ public class BufferedImageGraphics extends CairoGraphics2D int minY = image.getRaster().getSampleModelTranslateY(); // Pull pixels directly out of data buffer - if(raster instanceof CairoSurface) - pixels = ((CairoSurface)raster).getPixels(raster.getWidth() * raster.getHeight()); - else - pixels = ((DataBufferInt)raster.getDataBuffer()).getData(); + pixels = ((DataBufferInt)raster.getDataBuffer()).getData(); // Discard pixels that fall outside of the image's bounds // (ie, this image is actually a subimage of a different image) @@ -161,7 +153,8 @@ public class BufferedImageGraphics extends CairoGraphics2D int scanline = sm.getScanlineStride(); for (int i = 0; i < imageHeight; i++) - System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2, i * imageWidth, imageWidth); + System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2, + i * imageWidth, imageWidth); pixels = pixels2; } @@ -173,11 +166,13 @@ public class BufferedImageGraphics extends CairoGraphics2D } else { - pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(),image.getData()); + pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(), + image.getData()); + if (pixels != null) + System.arraycopy(pixels, 0, surface.getData(), + 0, pixels.length); } - surface.setPixels( pixels ); - setup( cairo_t ); setClip(0, 0, imageWidth, imageHeight); } @@ -189,7 +184,6 @@ public class BufferedImageGraphics extends CairoGraphics2D cairo_t = surface.newCairoContext(); imageWidth = copyFrom.imageWidth; imageHeight = copyFrom.imageHeight; - locked = false; hasFastCM = copyFrom.hasFastCM; hasAlpha = copyFrom.hasAlpha; @@ -202,17 +196,14 @@ public class BufferedImageGraphics extends CairoGraphics2D */ private void updateBufferedImage(int x, int y, int width, int height) { - if (locked) - return; - - double[] points = new double[]{x, y, width+x, height+y}; - transform.transform(points, 0, points, 0, 2); - x = (int)points[0]; - y = (int)points[1]; - width = (int)Math.ceil(points[2] - points[0]); - height = (int)Math.ceil(points[3] - points[1]); + Rectangle bounds = new Rectangle(x, y, width, height); + bounds = getTransformedBounds(bounds, transform).getBounds(); + x = bounds.x; + y = bounds.y; + width = bounds.width; + height = bounds.height; - int[] pixels = surface.getPixels(imageWidth * imageHeight); + int[] pixels = surface.getData(); if( x > imageWidth || y > imageHeight ) return; @@ -403,14 +394,10 @@ public class BufferedImageGraphics extends CairoGraphics2D BufferedImage bImg = (BufferedImage) img; // Find translated bounds - Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); - Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(), - bImg.getHeight() + bImg.getMinY()); + Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(), + bImg.getWidth(), bImg.getHeight()); if (xform != null) - { - origin = xform.transform(origin, origin); - pt = xform.transform(pt, pt); - } + bounds = getTransformedBounds(bounds, xform); // Create buffer and draw image createBuffer(); @@ -420,10 +407,7 @@ public class BufferedImageGraphics extends CairoGraphics2D g2d.drawImage(img, xform, obs); // Perform compositing - return drawComposite(new Rectangle2D.Double(origin.getX(), - origin.getY(), - pt.getX(), pt.getY()), - obs); + return drawComposite(bounds, obs); } } @@ -438,6 +422,11 @@ public class BufferedImageGraphics extends CairoGraphics2D if (comp == null || comp instanceof AlphaComposite) { super.drawGlyphVector(gv, x, y); + + // this returns an integer-based Rectangle (rather than a + // Rectangle2D), which takes care of any necessary rounding for us. + bounds = bounds.getBounds(); + updateBufferedImage((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight()); } @@ -468,12 +457,7 @@ public class BufferedImageGraphics extends CairoGraphics2D private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) { // Find bounds in device space - double[] points = new double[] {bounds.getX(), bounds.getY(), - bounds.getMaxX(), bounds.getMaxY()}; - transform.transform(points, 0, points, 0, 2); - bounds = new Rectangle2D.Double(points[0], points[1], - (points[2] - points[0]), - (points[3] - points[1])); + bounds = getTransformedBounds(bounds, transform); // Clip bounds by the stored clip, and by the internal buffer Rectangle2D devClip = this.getClipInDevSpace(); @@ -482,17 +466,15 @@ public class BufferedImageGraphics extends CairoGraphics2D buffer.getWidth(), buffer.getHeight()); Rectangle2D.intersect(bounds, devClip, bounds); - // Round bounds as needed, but be conservative in our rounding + // Round bounds as needed, but be careful in our rounding // (otherwise it may leave unpainted stripes) double x = bounds.getX(); double y = bounds.getY(); - double w = bounds.getWidth(); - double h = bounds.getHeight(); - if (Math.floor(x) != x) - w--; - if (Math.floor(y) != y) - h--; - bounds.setRect(Math.ceil(x), Math.ceil(y), Math.floor(w), Math.floor(h)); + double maxX = x + bounds.getWidth(); + double maxY = y + bounds.getHeight(); + x = Math.round(x); + y = Math.round(y); + bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y)); // Find subimage of internal buffer for updating BufferedImage buffer2 = buffer; @@ -511,9 +493,10 @@ public class BufferedImageGraphics extends CairoGraphics2D compCtx.compose(buffer2.getRaster(), current.getRaster(), current.getRaster()); - // Prevent the clearRect in CairoGraphics2D.drawImage from clearing - // our composited image - locked = true; + // Set cairo's composite to direct SRC, since we've already done our own + // compositing + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); // This MUST call directly into the "action" method in CairoGraphics2D, // not one of the wrappers, to ensure that the composite isn't processed @@ -521,8 +504,9 @@ public class BufferedImageGraphics extends CairoGraphics2D boolean rv = super.drawImage(current, AffineTransform.getTranslateInstance(bounds.getX(), bounds.getY()), - new Color(0,0,0,0), null); - locked = false; + null, null); + setComposite(oldcomp); + updateColor(); return rv; } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java index 4a6ad008259..3a386075a69 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -172,6 +172,12 @@ public abstract class CairoGraphics2D extends Graphics2D * Rendering hint map. */ private RenderingHints hints; + + /** + * Status of the anti-alias flag in cairo. + */ + private boolean antialias = false; + private boolean ignoreAA = false; /** * Some operations (drawing rather than filling) require that their @@ -228,6 +234,7 @@ public abstract class CairoGraphics2D extends Graphics2D setPaint(Color.black); setStroke(new BasicStroke()); setTransform(new AffineTransform()); + cairoSetAntialias(nativePointer, antialias); } /** @@ -244,7 +251,7 @@ public abstract class CairoGraphics2D extends Graphics2D if (g.fg.getAlpha() != -1) foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(), - g.fg.getAlpha()); + g.fg.getAlpha()); else foreground = new Color(g.fg.getRGB()); @@ -274,6 +281,9 @@ public abstract class CairoGraphics2D extends Graphics2D setTransformImpl(transform); setClip(clip); setComposite(comp); + + antialias = !g.antialias; + setAntialias(g.antialias); } /** @@ -311,8 +321,8 @@ public abstract class CairoGraphics2D extends Graphics2D public abstract GraphicsConfiguration getDeviceConfiguration(); - protected abstract void copyAreaImpl(int x, int y, - int width, int height, int dx, int dy); + protected abstract void copyAreaImpl(int x, int y, int width, int height, + int dx, int dy); /** @@ -345,8 +355,8 @@ public abstract class CairoGraphics2D extends Graphics2D int g2, int b2, int a2, boolean cyclic); protected native void setPaintPixels(long pointer, int[] pixels, int w, - int h, int stride, boolean repeat, - int x, int y); + int h, int stride, boolean repeat, + int x, int y); /** * Set the current transform matrix @@ -390,9 +400,9 @@ public abstract class CairoGraphics2D extends Graphics2D /* * Draws a Glyph Vector */ - native void cairoDrawGlyphVector(long pointer, GdkFontPeer font, + protected native void cairoDrawGlyphVector(long pointer, GdkFontPeer font, float x, float y, int n, - int[] codes, float[] positions); + int[] codes, float[] positions, long[] fontset); /** * Set the font in cairo. @@ -454,9 +464,15 @@ public abstract class CairoGraphics2D extends Graphics2D protected native void cairoClip(long pointer); /** - * Save clip + * Clear clip */ protected native void cairoResetClip(long pointer); + + /** + * Set antialias. + */ + protected native void cairoSetAntialias(long pointer, boolean aa); + ///////////////////////// TRANSFORMS /////////////////////////////////// /** @@ -648,33 +664,35 @@ public abstract class CairoGraphics2D extends Graphics2D setColor((Color) paint); customPaint = false; } + else if (paint instanceof TexturePaint) { - TexturePaint tp = (TexturePaint) paint; - BufferedImage img = tp.getImage(); + TexturePaint tp = (TexturePaint) paint; + BufferedImage img = tp.getImage(); - // map the image to the anchor rectangle - int width = (int) tp.getAnchorRect().getWidth(); - int height = (int) tp.getAnchorRect().getHeight(); + // map the image to the anchor rectangle + int width = (int) tp.getAnchorRect().getWidth(); + int height = (int) tp.getAnchorRect().getHeight(); - double scaleX = width / (double) img.getWidth(); - double scaleY = height / (double) img.getHeight(); + double scaleX = width / (double) img.getWidth(); + double scaleY = height / (double) img.getHeight(); - AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); - AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); - BufferedImage texture = op.filter(img, null); - int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); - setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0); + AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); + AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); + BufferedImage texture = op.filter(img, null); + int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); + setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0); customPaint = false; } + else if (paint instanceof GradientPaint) { - GradientPaint gp = (GradientPaint) paint; - Point2D p1 = gp.getPoint1(); - Point2D p2 = gp.getPoint2(); - Color c1 = gp.getColor1(); - Color c2 = gp.getColor2(); - setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(), + GradientPaint gp = (GradientPaint) paint; + Point2D p1 = gp.getPoint1(); + Point2D p2 = gp.getPoint2(); + Color c1 = gp.getColor1(); + Color c2 = gp.getColor2(); + setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(), c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(), c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(), gp.isCyclic()); @@ -703,15 +721,11 @@ public abstract class CairoGraphics2D extends Graphics2D int userHeight = bounds.height; // Find bounds in device space - Point2D origin = transform.transform(new Point2D.Double(userX, userY), - null); - Point2D extreme = transform.transform(new Point2D.Double(userWidth + userX, - userHeight + userY), - null); - int deviceX = (int)origin.getX(); - int deviceY = (int)origin.getY(); - int deviceWidth = (int)Math.ceil(extreme.getX() - origin.getX()); - int deviceHeight = (int)Math.ceil(extreme.getY() - origin.getY()); + Rectangle2D bounds2D = getTransformedBounds(bounds, transform); + int deviceX = (int)bounds2D.getX(); + int deviceY = (int)bounds2D.getY(); + int deviceWidth = (int)Math.ceil(bounds2D.getWidth()); + int deviceHeight = (int)Math.ceil(bounds2D.getHeight()); // Get raster of the paint background PaintContext pc = paint.createContext(CairoSurface.cairoColorModel, @@ -792,21 +806,22 @@ public abstract class CairoGraphics2D extends Graphics2D stroke = st; if (stroke instanceof BasicStroke) { - BasicStroke bs = (BasicStroke) stroke; - cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(), - bs.getLineJoin(), bs.getMiterLimit()); - - float[] dashes = bs.getDashArray(); - if (dashes != null) - { - double[] double_dashes = new double[dashes.length]; - for (int i = 0; i < dashes.length; i++) - double_dashes[i] = dashes[i]; - cairoSetDash(nativePointer, double_dashes, double_dashes.length, - (double) bs.getDashPhase()); - } - else - cairoSetDash(nativePointer, new double[0], 0, 0.0); + BasicStroke bs = (BasicStroke) stroke; + cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(), + bs.getLineJoin(), bs.getMiterLimit()); + + float[] dashes = bs.getDashArray(); + if (dashes != null) + { + double[] double_dashes = new double[dashes.length]; + for (int i = 0; i < dashes.length; i++) + double_dashes[i] = dashes[i]; + + cairoSetDash(nativePointer, double_dashes, double_dashes.length, + (double) bs.getDashPhase()); + } + else + cairoSetDash(nativePointer, new double[0], 0, 0.0); } } @@ -864,6 +879,7 @@ public abstract class CairoGraphics2D extends Graphics2D { if (fg == null) fg = Color.BLACK; + cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0, fg.getGreen() / 255.0,fg.getBlue() / 255.0, fg.getAlpha() / 255.0); @@ -916,18 +932,7 @@ public abstract class CairoGraphics2D extends Graphics2D if (transform == null) return uclip; else - { - Point2D pos = transform.transform(new Point2D.Double(uclip.getX(), - uclip.getY()), - (Point2D) null); - Point2D extent = transform.deltaTransform(new Point2D.Double(uclip - .getWidth(), - uclip - .getHeight()), - (Point2D) null); - return new Rectangle2D.Double(pos.getX(), pos.getY(), extent.getX(), - extent.getY()); - } + return getTransformedBounds(clip.getBounds2D(), transform); } public void setClip(int x, int y, int width, int height) @@ -946,8 +951,8 @@ public abstract class CairoGraphics2D extends Graphics2D // initial clip properly. if( firstClip ) { - originalClip = s; - firstClip = false; + originalClip = s; + firstClip = false; } clip = s; @@ -1007,7 +1012,7 @@ public abstract class CairoGraphics2D extends Graphics2D if (comp instanceof AlphaComposite) { - AlphaComposite a = (AlphaComposite) comp; + AlphaComposite a = (AlphaComposite) comp; cairoSetOperator(nativePointer, a.getRule()); } @@ -1066,7 +1071,9 @@ public abstract class CairoGraphics2D extends Graphics2D Rectangle r = findStrokedBounds(s); setCustomPaint(r); } - + + setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING) + .equals(RenderingHints.VALUE_ANTIALIAS_OFF)); createPath(s, true); cairoStroke(nativePointer); } @@ -1077,7 +1084,9 @@ public abstract class CairoGraphics2D extends Graphics2D if (customPaint) setCustomPaint(s.getBounds()); - + + setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING) + .equals(RenderingHints.VALUE_ANTIALIAS_OFF)); double alpha = 1.0; if (comp instanceof AlphaComposite) alpha = ((AlphaComposite) comp).getAlpha(); @@ -1263,13 +1272,15 @@ public abstract class CairoGraphics2D extends Graphics2D public void copyArea(int ox, int oy, int owidth, int oheight, int odx, int ody) { + // FIXME: does this handle a rotation transform properly? + // (the width/height might not be correct) Point2D pos = transform.transform(new Point2D.Double(ox, oy), - (Point2D) null); + (Point2D) null); Point2D dim = transform.transform(new Point2D.Double(ox + owidth, - oy + oheight), - (Point2D) null); + oy + oheight), + (Point2D) null); Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody), - (Point2D) null); + (Point2D) null); int x = (int)pos.getX(); int y = (int)pos.getY(); int width = (int)(dim.getX() - pos.getX()); @@ -1291,14 +1302,14 @@ public abstract class CairoGraphics2D extends Graphics2D // Clip edges if necessary if( x + dx < r.getX() ) // left { - width = x + dx + width; - x = (int)r.getX() - dx; + width = x + dx + width; + x = (int)r.getX() - dx; } if( y + dy < r.getY() ) // top { - height = y + dy + height; - y = (int)r.getY() - dy; + height = y + dy + height; + y = (int)r.getY() - dy; } if( x + dx + width >= r.getWidth() ) // right @@ -1325,10 +1336,10 @@ public abstract class CairoGraphics2D extends Graphics2D return hints.get(hintKey); } - public void setRenderingHints(Map hints) + public void setRenderingHints(Map<?,?> hints) { this.hints = new RenderingHints(getDefaultHints()); - this.hints.add(new RenderingHints(hints)); + this.hints.putAll(hints); shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); @@ -1342,7 +1353,7 @@ public abstract class CairoGraphics2D extends Graphics2D public void addRenderingHints(Map hints) { - this.hints.add(new RenderingHints(hints)); + this.hints.putAll(hints); } public RenderingHints getRenderingHints() @@ -1373,6 +1384,24 @@ public abstract class CairoGraphics2D extends Graphics2D // Do bilinear interpolation as default return INTERPOLATION_BILINEAR; } + + /** + * Set antialias if needed. If the ignoreAA flag is set, this method will + * return without doing anything. + * + * @param needAA RenderingHints.VALUE_ANTIALIAS_ON or RenderingHints.VALUE_ANTIALIAS_OFF + */ + private void setAntialias(boolean needAA) + { + if (ignoreAA) + return; + + if (needAA != antialias) + { + antialias = !antialias; + cairoSetAntialias(nativePointer, antialias); + } + } ///////////////////////// IMAGE. METHODS /////////////////////////////////// @@ -1396,12 +1425,12 @@ public abstract class CairoGraphics2D extends Graphics2D try { - invertedXform = xform.createInverse(); + invertedXform = xform.createInverse(); } catch (NoninvertibleTransformException e) { - throw new ImagingOpException("Unable to invert transform " - + xform.toString()); + throw new ImagingOpException("Unable to invert transform " + + xform.toString()); } // Unrecognized image - convert to a BufferedImage @@ -1411,10 +1440,10 @@ public abstract class CairoGraphics2D extends Graphics2D img = AsyncImage.realImage(img, obs); if( !(img instanceof BufferedImage) ) { - ImageProducer source = img.getSource(); - if (source == null) - return false; - img = Toolkit.getDefaultToolkit().createImage(source); + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); } BufferedImage b = (BufferedImage) img; @@ -1427,7 +1456,7 @@ public abstract class CairoGraphics2D extends Graphics2D // use the cached CairoSurface that BIG is drawing onto if( BufferedImageGraphics.bufferedImages.get( b ) != null ) - raster = (Raster)BufferedImageGraphics.bufferedImages.get( b ); + raster = BufferedImageGraphics.bufferedImages.get( b ); else raster = b.getRaster(); @@ -1437,12 +1466,12 @@ public abstract class CairoGraphics2D extends Graphics2D if (comp instanceof AlphaComposite) alpha = ((AlphaComposite) comp).getAlpha(); - if(raster instanceof CairoSurface) + if(raster instanceof CairoSurface + && ((CairoSurface)raster).sharedBuffer == true) { - ((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha, - getInterpolation()); + drawCairoSurface((CairoSurface)raster, xform, alpha, getInterpolation()); updateColor(); - return true; + return true; } if( bgcolor != null ) @@ -1450,24 +1479,31 @@ public abstract class CairoGraphics2D extends Graphics2D Color oldColor = bg; setBackground(bgcolor); - double[] origin = new double[] {0,0}; - double[] dimensions = new double[] {width, height}; - xform.transform(origin, 0, origin, 0, 1); - xform.deltaTransform(dimensions, 0, dimensions, 0, 1); - clearRect((int)origin[0], (int)origin[1], - (int)dimensions[0], (int)dimensions[1]); + Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); + bounds = getTransformedBounds(bounds, xform); + + clearRect((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), (int)bounds.getHeight()); setBackground(oldColor); } int[] pixels = b.getRGB(0, 0, width, height, null, 0, width); - // FIXME: The above method returns data in the standard ARGB colorspace, // meaning data should NOT be alpha pre-multiplied; however Cairo expects // data to be premultiplied. + + cairoSave(nativePointer); + Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); + bounds = getTransformedBounds(bounds, xform); + cairoRectangle(nativePointer, bounds.getX(), bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + cairoClip(nativePointer); drawPixels(nativePointer, pixels, width, height, width, i2u, alpha, getInterpolation()); + + cairoRestore(nativePointer); // Cairo seems to lose the current color which must be restored. updateColor(); @@ -1578,6 +1614,66 @@ public abstract class CairoGraphics2D extends Graphics2D { return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); } + + /** + * Optimized method for drawing a CairoSurface onto this graphics context. + * + * @param surface The surface to draw. + * @param tx The transformation matrix (cannot be null). + * @param alpha The alpha value to paint with ( 0 <= alpha <= 1). + * @param interpolation The interpolation type. + */ + protected void drawCairoSurface(CairoSurface surface, AffineTransform tx, + double alpha, int interpolation) + { + // Find offset required if this surface is a sub-raster, and append offset + // to transformation. + if (surface.getSampleModelTranslateX() != 0 + || surface.getSampleModelTranslateY() != 0) + { + Point2D origin = new Point2D.Double(0, 0); + Point2D offset = new Point2D.Double(surface.getSampleModelTranslateX(), + surface.getSampleModelTranslateY()); + + tx.transform(origin, origin); + tx.transform(offset, offset); + + tx.translate(offset.getX() - origin.getX(), + offset.getY() - origin.getY()); + } + + // Find dimensions of this surface relative to the root parent surface + Rectangle bounds = new Rectangle(-surface.getSampleModelTranslateX(), + -surface.getSampleModelTranslateY(), + surface.width, surface.height); + + // Clip to the translated image + // We use direct cairo methods to avoid the overhead of maintaining a + // java copy of the clip, since we will be reverting it immediately + // after drawing + Shape newBounds = tx.createTransformedShape(bounds); + cairoSave(nativePointer); + walkPath(newBounds.getPathIterator(null), false); + cairoClip(nativePointer); + + // Draw the surface + try + { + double[] i2u = new double[6]; + tx.createInverse().getMatrix(i2u); + surface.nativeDrawSurface(surface.surfacePointer, nativePointer, i2u, + alpha, interpolation); + } + catch (NoninvertibleTransformException ex) + { + // This should never happen(?), so we don't need to do anything here. + ; + } + + // Restore clip + cairoRestore(nativePointer); + } + ///////////////////////// TEXT METHODS //////////////////////////////////// @@ -1592,7 +1688,15 @@ public abstract class CairoGraphics2D extends Graphics2D tl = new TextLayout( str, getFont(), getFontRenderContext() ); fontPeer.textLayoutCache.put(str, tl); } + + // Set antialias to text_antialiasing, and set the ignoreAA flag so that + // the setting doesn't get overridden in a draw() or fill() call. + setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING) + .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); + ignoreAA = true; + tl.draw(this, x, y); + ignoreAA = false; } public void drawString(String str, int x, int y) @@ -1617,19 +1721,25 @@ public abstract class CairoGraphics2D extends Graphics2D if (comp instanceof AlphaComposite) alpha = ((AlphaComposite) comp).getAlpha(); + + setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING) + .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); + ignoreAA = true; + if (gv instanceof FreetypeGlyphVector && alpha == 1.0) { int n = gv.getNumGlyphs (); int[] codes = gv.getGlyphCodes (0, n, null); + long[] fontset = ((FreetypeGlyphVector)gv).getGlyphFonts (0, n, null); float[] positions = gv.getGlyphPositions (0, n, null); setFont (gv.getFont ()); GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer(); - synchronized (fontPeer) - { - cairoDrawGlyphVector(nativePointer, fontPeer, - x, y, n, codes, positions); - } + synchronized (fontPeer) + { + cairoDrawGlyphVector(nativePointer, fontPeer, + x, y, n, codes, positions, fontset); + } } else { @@ -1637,6 +1747,8 @@ public abstract class CairoGraphics2D extends Graphics2D fill(gv.getOutline()); translate(-x, -y); } + + ignoreAA = false; } public void drawString(AttributedCharacterIterator ci, float x, float y) @@ -1702,9 +1814,9 @@ public abstract class CairoGraphics2D extends Graphics2D { if( onStroke ) { - Shape stroked = stroke.createStrokedShape( s ); - return stroked.intersects( (double)rect.x, (double)rect.y, - (double)rect.width, (double)rect.height ); + Shape stroked = stroke.createStrokedShape( s ); + return stroked.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); } return s.intersects( (double)rect.x, (double)rect.y, (double)rect.width, (double)rect.height ); @@ -1747,34 +1859,34 @@ public abstract class CairoGraphics2D extends Graphics2D imageToUser.getMatrix(i2u); else { - i2u[0] = 1; - i2u[1] = 0; - i2u[2] = 0; - i2u[3] = 1; - i2u[4] = 0; - i2u[5] = 0; + i2u[0] = 1; + i2u[1] = 0; + i2u[2] = 0; + i2u[3] = 1; + i2u[4] = 0; + i2u[5] = 0; } int[] pixels = findSimpleIntegerArray(cm, r); if (pixels == null) { - // FIXME: I don't think this code will work correctly with a non-RGB - // MultiPixelPackedSampleModel. Although this entire method should - // probably be rewritten to better utilize Cairo's different supported - // data formats. - if (sm instanceof MultiPixelPackedSampleModel) - { - pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels); - for (int i = 0; i < pixels.length; i++) - pixels[i] = cm.getRGB(pixels[i]); - } - else - { - pixels = new int[r.getWidth() * r.getHeight()]; - for (int i = 0; i < pixels.length; i++) - pixels[i] = cm.getRGB(db.getElem(i)); - } + // FIXME: I don't think this code will work correctly with a non-RGB + // MultiPixelPackedSampleModel. Although this entire method should + // probably be rewritten to better utilize Cairo's different supported + // data formats. + if (sm instanceof MultiPixelPackedSampleModel) + { + pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels); + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(pixels[i]); + } + else + { + pixels = new int[r.getWidth() * r.getHeight()]; + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(db.getElem(i)); + } } // Change all transparent pixels in the image to the specified bgcolor, @@ -1782,20 +1894,21 @@ public abstract class CairoGraphics2D extends Graphics2D // correctly. if (cm.hasAlpha()) { - if (bgcolor != null && cm.hasAlpha()) - for (int i = 0; i < pixels.length; i++) - { - if (cm.getAlpha(pixels[i]) == 0) - pixels[i] = bgcolor.getRGB(); - } + if (bgcolor != null && cm.hasAlpha()) + for (int i = 0; i < pixels.length; i++) + { + if (cm.getAlpha(pixels[i]) == 0) + pixels[i] = bgcolor.getRGB(); + } } else for (int i = 0; i < pixels.length; i++) - pixels[i] |= 0xFF000000; + pixels[i] |= 0xFF000000; double alpha = 1.0; if (comp instanceof AlphaComposite) alpha = ((AlphaComposite) comp).getAlpha(); + drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(), r.getWidth(), i2u, alpha, getInterpolation()); @@ -1815,7 +1928,7 @@ public abstract class CairoGraphics2D extends Graphics2D double shift = 0.5; if (!transform.isIdentity()) shift /= transform.getScaleX(); - return Math.round(coord) + shift; + return (coord + shift); } else return coord; @@ -1831,7 +1944,7 @@ public abstract class CairoGraphics2D extends Graphics2D double shift = 0.5; if (!transform.isIdentity()) shift /= transform.getScaleY(); - return Math.round(coord) + shift; + return (coord + shift); } else return coord; @@ -1849,53 +1962,54 @@ public abstract class CairoGraphics2D extends Graphics2D cairoSetFillRule(nativePointer, p.getWindingRule()); for (; ! p.isDone(); p.next()) { - int seg = p.currentSegment(coords); - switch (seg) - { - case PathIterator.SEG_MOVETO: - x = shiftX(coords[0], doShift); - y = shiftY(coords[1], doShift); - cairoMoveTo(nativePointer, x, y); - break; - case PathIterator.SEG_LINETO: - x = shiftX(coords[0], doShift); - y = shiftY(coords[1], doShift); - cairoLineTo(nativePointer, x, y); - break; - case PathIterator.SEG_QUADTO: - // splitting a quadratic bezier into a cubic: - // see: http://pfaedit.sourceforge.net/bezier.html - double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x); - double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y); - - double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x); - double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y); - - x = shiftX(coords[2], doShift); - y = shiftY(coords[3], doShift); - cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y); - break; - case PathIterator.SEG_CUBICTO: - x = shiftX(coords[4], doShift); - y = shiftY(coords[5], doShift); - cairoCurveTo(nativePointer, shiftX(coords[0], doShift), - shiftY(coords[1], doShift), - shiftX(coords[2], doShift), - shiftY(coords[3], doShift), x, y); - break; - case PathIterator.SEG_CLOSE: - cairoClosePath(nativePointer); - break; - } + int seg = p.currentSegment(coords); + switch (seg) + { + case PathIterator.SEG_MOVETO: + x = shiftX(coords[0], doShift); + y = shiftY(coords[1], doShift); + cairoMoveTo(nativePointer, x, y); + break; + case PathIterator.SEG_LINETO: + x = shiftX(coords[0], doShift); + y = shiftY(coords[1], doShift); + cairoLineTo(nativePointer, x, y); + break; + case PathIterator.SEG_QUADTO: + // splitting a quadratic bezier into a cubic: + // see: http://pfaedit.sourceforge.net/bezier.html + double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x); + double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y); + + double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x); + double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y); + + x = shiftX(coords[2], doShift); + y = shiftY(coords[3], doShift); + cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y); + break; + case PathIterator.SEG_CUBICTO: + x = shiftX(coords[4], doShift); + y = shiftY(coords[5], doShift); + cairoCurveTo(nativePointer, shiftX(coords[0], doShift), + shiftY(coords[1], doShift), + shiftX(coords[2], doShift), + shiftY(coords[3], doShift), x, y); + break; + case PathIterator.SEG_CLOSE: + cairoClosePath(nativePointer); + break; + } } } /** * Used by setRenderingHints() */ - private Map getDefaultHints() + private Map<RenderingHints.Key, Object> getDefaultHints() { - HashMap defaultHints = new HashMap(); + HashMap<RenderingHints.Key, Object> defaultHints = + new HashMap<RenderingHints.Key, Object>(); defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); @@ -1972,11 +2086,27 @@ public abstract class CairoGraphics2D extends Graphics2D if (clip == null) return; - if (! (clip instanceof GeneralPath)) - clip = new GeneralPath(clip); - - GeneralPath p = (GeneralPath) clip; - p.transform(t); + // If the clip is a rectangle, and the transformation preserves the shape + // (translate/stretch only), then keep the clip as a rectangle + double[] matrix = new double[4]; + t.getMatrix(matrix); + if (clip instanceof Rectangle2D && matrix[1] == 0 && matrix[2] == 0) + { + Rectangle2D rect = (Rectangle2D)clip; + double[] origin = new double[] {rect.getX(), rect.getY()}; + double[] dimensions = new double[] {rect.getWidth(), rect.getHeight()}; + t.transform(origin, 0, origin, 0, 1); + t.deltaTransform(dimensions, 0, dimensions, 0, 1); + rect.setRect(origin[0], origin[1], dimensions[0], dimensions[1]); + } + else + { + if (! (clip instanceof GeneralPath)) + clip = new GeneralPath(clip); + + GeneralPath p = (GeneralPath) clip; + p.transform(t); + } } private static Rectangle computeIntersection(int x, int y, int w, int h, @@ -1999,4 +2129,39 @@ public abstract class CairoGraphics2D extends Graphics2D return rect; } + + static Rectangle2D getTransformedBounds(Rectangle2D bounds, AffineTransform tx) + { + double x1 = bounds.getX(); + double x2 = bounds.getX() + bounds.getWidth(); + double x3 = x1; + double x4 = x2; + double y1 = bounds.getY(); + double y2 = y1; + double y3 = bounds.getY() + bounds.getHeight(); + double y4 = y3; + + double[] points = new double[] {x1, y1, x2, y2, x3, y3, x4, y4}; + tx.transform(points, 0, points, 0, 4); + + double minX = points[0]; + double maxX = minX; + double minY = points[1]; + double maxY = minY; + for (int i = 0; i < 8; i++) + { + if (points[i] < minX) + minX = points[i]; + if (points[i] > maxX) + maxX = points[i]; + i++; + + if (points[i] < minY) + minY = points[i]; + if (points[i] > maxY) + maxY = points[i]; + } + + return new Rectangle2D.Double(minX, minY, (maxX - minX), (maxY - minY)); + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java index 5b63e62e7ed..b45a79fd6e7 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java @@ -1,5 +1,5 @@ /* CairoSurface.java - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,15 +42,22 @@ import gnu.java.awt.Buffers; import java.awt.Graphics2D; import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.WritableRaster; import java.nio.ByteOrder; +import java.util.Arrays; import java.util.Hashtable; /** @@ -68,9 +75,9 @@ public class CairoSurface extends WritableRaster long surfacePointer; /** - * The native pointer to the image's data buffer + * Whether the data buffer is shared between java and cairo. */ - long bufferPointer; + boolean sharedBuffer; // FIXME: use only the cairoCM_pre colormodel // since that's what Cairo really uses (is there a way to do this cheaply? @@ -98,22 +105,12 @@ public class CairoSurface extends WritableRaster * @param width, height - the image size * @param stride - the buffer row stride. (in ints) */ - private native void create(int width, int height, int stride); + private native void create(int width, int height, int stride, int[] buf); /** * Destroys the cairo surface and frees the buffer. */ - private native void destroy(long surfacePointer, long bufferPointer); - - /** - * Gets buffer elements - */ - private native int nativeGetElem(long bufferPointer, int i); - - /** - * Sets buffer elements. - */ - private native void nativeSetElem(long bufferPointer, int i, int val); + private native void destroy(long surfacePointer, int[] buf); /** * Draws this image to a given CairoGraphics context, @@ -123,33 +120,30 @@ public class CairoSurface extends WritableRaster double[] i2u, double alpha, int interpolation); - public void drawSurface(long contextPointer, double[] i2u, double alpha, - int interpolation) - { - nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha, interpolation); - } - /** - * getPixels -return the pixels as a java array. + * Synchronizes the image's data buffers, copying any changes made in the + * Java array into the native array. + * + * This method should only be called if (sharedBuffers == false). */ - native int[] nativeGetPixels(long bufferPointer, int size); - - public int[] getPixels(int size) - { - return nativeGetPixels(bufferPointer, size); - } - + native void syncNativeToJava(long surfacePointer, int[] buffer); + /** - * getPixels -return the pixels as a java array. + * Synchronizes the image's data buffers, copying any changes made in the + * native array into the Java array. + * + * This method should only be called if (sharedBuffers == false). */ - native void nativeSetPixels(long bufferPointer, int[] pixels); - - public void setPixels(int[] pixels) - { - nativeSetPixels(bufferPointer, pixels); - } - - native long getFlippedBuffer(long bufferPointer, int size); + native void syncJavaToNative(long surfacePointer, int[] buffer); + + /** + * Return the buffer, with the sample values of each pixel reversed + * (ie, in ABGR instead of ARGB). + * + * @return A pointer to a flipped buffer. The memory is allocated in native + * code, and must be explicitly freed when it is no longer needed. + */ + native long getFlippedBuffer(long surfacePointer); /** * Create a cairo_surface_t with specified width and height. @@ -158,20 +152,38 @@ public class CairoSurface extends WritableRaster */ public CairoSurface(int width, int height) { - super(createCairoSampleModel(width, height), - null, new Point(0, 0)); + this(0, 0, width, height); + } + + public CairoSurface(int x, int y, int width, int height) + { + super(createCairoSampleModel(width, height), null, new Point(x, y)); if(width <= 0 || height <= 0) throw new IllegalArgumentException("Image must be at least 1x1 pixels."); this.width = width; this.height = height; - create(width, height, width); + dataBuffer = new DataBufferInt(width * height); + create(width, height, width, getData()); - if(surfacePointer == 0 || bufferPointer == 0) + if(surfacePointer == 0) throw new Error("Could not allocate bitmap."); - - dataBuffer = new CairoDataBuffer(); + } + + /** + * Create a Cairo Surface that is a subimage of another Cairo Surface + */ + public CairoSurface(SampleModel sm, CairoSurface parent, Rectangle bounds, + Point origin) + { + super(sm, parent.dataBuffer, bounds, origin, parent); + + this.width = super.width; + this.height = super.height; + this.surfacePointer = parent.surfacePointer; + this.sharedBuffer = parent.sharedBuffer; + this.dataBuffer = parent.dataBuffer; } /** @@ -188,39 +200,39 @@ public class CairoSurface extends WritableRaster // Swap ordering from GdkPixbuf to Cairo if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { - for (int i = 0; i < data.length; i++ ) - { - // On a big endian system we get a RRGGBBAA data array. - int alpha = data[i] & 0xFF; - if( alpha == 0 ) // I do not know why we need this, but it works. - data[i] = 0; - else - { - // Cairo needs a ARGB32 native array. - data[i] = (data[i] >>> 8) | (alpha << 24); - } - } + for (int i = 0; i < data.length; i++ ) + { + // On a big endian system we get a RRGGBBAA data array. + int alpha = data[i] & 0xFF; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + // Cairo needs a ARGB32 native array. + data[i] = (data[i] >>> 8) | (alpha << 24); + } + } } else { - for (int i = 0; i < data.length; i++ ) - { - // On a little endian system we get a AABBGGRR data array. - int alpha = data[i] & 0xFF000000; - if( alpha == 0 ) // I do not know why we need this, but it works. - data[i] = 0; - else - { - int b = (data[i] & 0xFF0000) >> 16; - int g = (data[i] & 0xFF00); - int r = (data[i] & 0xFF) << 16; - // Cairo needs a ARGB32 native array. - data[i] = alpha | r | g | b; - } - } + for (int i = 0; i < data.length; i++ ) + { + // On a little endian system we get a AABBGGRR data array. + int alpha = data[i] & 0xFF000000; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + int b = (data[i] & 0xFF0000) >> 16; + int g = (data[i] & 0xFF00); + int r = (data[i] & 0xFF) << 16; + // Cairo needs a ARGB32 native array. + data[i] = alpha | r | g | b; + } + } } - setPixels( data ); + System.arraycopy(data, 0, getData(), 0, data.length); } /** @@ -228,8 +240,8 @@ public class CairoSurface extends WritableRaster */ public void dispose() { - if(surfacePointer != 0) - destroy(surfacePointer, bufferPointer); + if(surfacePointer != 0 && parent == null) + destroy(surfacePointer, getData()); } /** @@ -245,8 +257,17 @@ public class CairoSurface extends WritableRaster */ public GtkImage getGtkImage() { - return new GtkImage( width, height, - getFlippedBuffer(bufferPointer, width * height )); + return new GtkImage(width, height, getFlippedBuffer(surfacePointer)); + } + + /** + * Convenience method to quickly grab the data array backing this Raster. + * + * @return The array behind the databuffer. + */ + public int[] getData() + { + return ((DataBufferInt)dataBuffer).getData(); } /** @@ -276,34 +297,6 @@ public class CairoSurface extends WritableRaster new Hashtable()); } - private class CairoDataBuffer extends DataBuffer - { - public CairoDataBuffer() - { - super(DataBuffer.TYPE_INT, width * height); - } - - /** - * DataBuffer.getElem implementation - */ - public int getElem(int bank, int i) - { - if(bank != 0 || i < 0 || i >= width * height) - throw new IndexOutOfBoundsException(i+" size: "+width * height); - return nativeGetElem(bufferPointer, i); - } - - /** - * DataBuffer.setElem implementation - */ - public void setElem(int bank, int i, int val) - { - if(bank != 0 || i < 0 || i >= width*height) - throw new IndexOutOfBoundsException(i+" size: "+width * height); - nativeSetElem(bufferPointer, i, val); - } - } - /** * Return a Graphics2D drawing to the CairoSurface. */ @@ -325,16 +318,25 @@ public class CairoSurface extends WritableRaster } /** - * Copy an area of the surface. Expects parameters must be within bounds. - * Count on a segfault otherwise. + * Copy a portion of this surface to another area on the surface. The given + * parameters must be within bounds - count on a segfault otherwise. + * + * @param x The x coordinate of the area to be copied from. + * @param y The y coordinate of the area to be copied from. + * @param width The width of the area to be copied. + * @param height The height of the area to be copied. + * @param dx The destination x coordinate. + * @param dy The destination y coordinate. + * @param stride The scanline stride. */ - native void copyAreaNative2(long bufferPointer, int x, int y, int width, - int height, int dx, int dy, int stride); public void copyAreaNative(int x, int y, int width, int height, int dx, int dy, int stride) { - copyAreaNative2(bufferPointer, x, y, width, height, dx, dy, stride); + copyAreaNative2(surfacePointer, x, y, width, height, dx, dy, stride); } + native void copyAreaNative2(long surfacePointer, + int x, int y, int width, int height, + int dx, int dy, int stride); /** * Creates a SampleModel that matches Cairo's native format @@ -345,4 +347,83 @@ public class CairoSurface extends WritableRaster new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}); } + + /** + * Returns whether this ColorModel is compatible with Cairo's native types. + * + * @param cm The color model to check. + * @return Whether it is compatible. + */ + public static boolean isCompatibleColorModel(ColorModel cm) + { + return (cm.equals(cairoCM_pre) || cm.equals(cairoCM_opaque) || + cm.equals(cairoColorModel)); + } + + /** + * Returns whether this SampleModel is compatible with Cairo's native types. + * + * @param sm The sample model to check. + * @return Whether it is compatible. + */ + public static boolean isCompatibleSampleModel(SampleModel sm) + { + return (sm instanceof SinglePixelPackedSampleModel + && sm.getDataType() == DataBuffer.TYPE_INT + && Arrays.equals(((SinglePixelPackedSampleModel)sm).getBitMasks(), + new int[]{0x00FF0000, 0x0000FF00, + 0x000000FF, 0xFF000000})); + } + + ///// Methods interhited from Raster and WritableRaster ///// + public Raster createChild(int parentX, int parentY, int width, int height, + int childMinX, int childMinY, int[] bandList) + { + return createWritableChild(parentX, parentY, width, height, + childMinX, childMinY, bandList); + } + + public WritableRaster createCompatibleWritableRaster() + { + return new CairoSurface(width, height); + } + + public WritableRaster createCompatibleWritableRaster (int x, int y, + int w, int h) + { + return new CairoSurface(x, y, w, h); + } + + public Raster createTranslatedChild(int childMinX, int childMinY) + { + return createWritableTranslatedChild(childMinX, childMinY); + } + + public WritableRaster createWritableChild(int parentX, int parentY, + int w, int h, int childMinX, + int childMinY, int[] bandList) + { + if (parentX < minX || parentX + w > minX + width + || parentY < minY || parentY + h > minY + height) + throw new RasterFormatException("Child raster extends beyond parent"); + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + return new CairoSurface(sm, this, + new Rectangle(childMinX, childMinY, w, h), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY)); + } + + public WritableRaster createWritableTranslatedChild(int x, int y) + { + int tcx = sampleModelTranslateX - minX + x; + int tcy = sampleModelTranslateY - minY + y; + + return new CairoSurface(sampleModel, this, + new Rectangle(x, y, width, height), + new Point(tcx, tcy)); + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java index 36743b9c2da..35b015f3200 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java @@ -40,6 +40,7 @@ package gnu.java.awt.peer.gtk; import java.awt.AlphaComposite; import java.awt.Color; +import java.awt.Composite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; @@ -50,7 +51,6 @@ import java.awt.Shape; import java.awt.Toolkit; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; @@ -116,6 +116,18 @@ public class CairoSurfaceGraphics extends CairoGraphics2D */ public void draw(Shape s) { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + // Find total bounds of shape + Rectangle r = findStrokedBounds(s); + if (shiftDrawCalls) + { + r.width++; + r.height++; + } + + // Do the drawing if (comp == null || comp instanceof AlphaComposite) super.draw(s); @@ -126,14 +138,21 @@ public class CairoSurfaceGraphics extends CairoGraphics2D Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setStroke(this.getStroke()); g2d.setColor(this.getColor()); + g2d.setTransform(transform); g2d.draw(s); - drawComposite(s.getBounds2D(), null); + drawComposite(r.getBounds2D(), null); } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); } public void fill(Shape s) { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + if (comp == null || comp instanceof AlphaComposite) super.fill(s); @@ -144,14 +163,21 @@ public class CairoSurfaceGraphics extends CairoGraphics2D Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setPaint(this.getPaint()); g2d.setColor(this.getColor()); + g2d.setTransform(transform); g2d.fill(s); drawComposite(s.getBounds2D(), null); } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); } public void drawRenderedImage(RenderedImage image, AffineTransform xform) { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + if (comp == null || comp instanceof AlphaComposite) super.drawRenderedImage(image, xform); @@ -161,18 +187,25 @@ public class CairoSurfaceGraphics extends CairoGraphics2D Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setRenderingHints(this.getRenderingHints()); + g2d.setTransform(transform); g2d.drawRenderedImage(image, xform); drawComposite(buffer.getRaster().getBounds(), null); } - + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); } protected boolean drawImage(Image img, AffineTransform xform, Color bgcolor, ImageObserver obs) { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + boolean ret; if (comp == null || comp instanceof AlphaComposite) - return super.drawImage(img, xform, bgcolor, obs); + ret = super.drawImage(img, xform, bgcolor, obs); else { @@ -187,14 +220,10 @@ public class CairoSurfaceGraphics extends CairoGraphics2D BufferedImage bImg = (BufferedImage) img; // Find translated bounds - Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); - Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(), - bImg.getHeight() + bImg.getMinY()); + Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(), + bImg.getWidth(), bImg.getHeight()); if (xform != null) - { - origin = xform.transform(origin, origin); - pt = xform.transform(pt, pt); - } + bounds = getTransformedBounds(bounds, xform); // Create buffer and draw image createBuffer(); @@ -204,15 +233,20 @@ public class CairoSurfaceGraphics extends CairoGraphics2D g2d.drawImage(img, xform, obs); // Perform compositing - return drawComposite(new Rectangle2D.Double(origin.getX(), - origin.getY(), - pt.getX(), pt.getY()), - obs); + ret = drawComposite(bounds, obs); } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + + return ret; } public void drawGlyphVector(GlyphVector gv, float x, float y) { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + if (comp == null || comp instanceof AlphaComposite) super.drawGlyphVector(gv, x, y); @@ -230,51 +264,64 @@ public class CairoSurfaceGraphics extends CairoGraphics2D bounds.getWidth(), bounds.getHeight()); drawComposite(bounds, null); } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); } private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) { - // Clip source to visible areas that need updating - Rectangle2D clip = this.getClipBounds(); - Rectangle2D.intersect(bounds, clip, bounds); - clip = new Rectangle(buffer.getMinX(), buffer.getMinY(), - buffer.getWidth(), buffer.getHeight()); - Rectangle2D.intersect(bounds, clip, bounds); + // Find bounds in device space + bounds = getTransformedBounds(bounds, transform); + + // Clip bounds by the stored clip, and by the internal buffer + Rectangle2D devClip = this.getClipInDevSpace(); + Rectangle2D.intersect(bounds, devClip, bounds); + devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, devClip, bounds); + + // Round bounds as needed, but be careful in our rounding + // (otherwise it may leave unpainted stripes) + double x = bounds.getX(); + double y = bounds.getY(); + double maxX = x + bounds.getWidth(); + double maxY = y + bounds.getHeight(); + x = Math.round(x); + y = Math.round(y); + bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y)); + // Find subimage of internal buffer for updating BufferedImage buffer2 = buffer; if (!bounds.equals(buffer2.getRaster().getBounds())) buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight()); - - // Get destination clip to bounds - double[] points = new double[] {bounds.getX(), bounds.getY(), - bounds.getMaxX(), bounds.getMaxY()}; - transform.transform(points, 0, points, 0, 2); - - Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], - points[2] - points[0], - points[3] - points[1]); - - Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); - + + // Find subimage of main image for updating BufferedImage current = CairoSurface.getBufferedImage(surface); - current = current.getSubimage((int)deviceBounds.getX(), - (int)deviceBounds.getY(), - (int)deviceBounds.getWidth(), - (int)deviceBounds.getHeight()); + current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); // Perform actual composite operation compCtx.compose(buffer2.getRaster(), current.getRaster(), buffer2.getRaster()); + // Set cairo's composite to direct SRC, since we've already done our own + // compositing + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + // This MUST call directly into the "action" method in CairoGraphics2D, // not one of the wrappers, to ensure that the composite isn't processed // more than once! boolean rv = super.drawImage(buffer2, AffineTransform.getTranslateInstance(bounds.getX(), bounds.getY()), - new Color(0,0,0,0), null); + null, null); + setComposite(oldcomp); + updateColor(); return rv; } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java index 8adf275ad44..e54320697d8 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -52,7 +52,6 @@ import java.awt.Shape; import java.awt.Toolkit; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; -import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; @@ -78,7 +77,7 @@ public class ComponentGraphics extends CairoGraphics2D protected long cairo_t; private BufferedImage buffer, componentBuffer; - private static ThreadLocal hasLock = new ThreadLocal(); + private static ThreadLocal<Integer> hasLock = new ThreadLocal<Integer>(); private static Integer ONE = Integer.valueOf(1); ComponentGraphics() @@ -122,11 +121,11 @@ public class ComponentGraphics extends CairoGraphics2D */ private void lock() { - Integer i = (Integer) hasLock.get(); + Integer i = hasLock.get(); if (i == null) { - start_gdk_drawing(); - hasLock.set(ONE); + start_gdk_drawing(); + hasLock.set(ONE); } else hasLock.set(Integer.valueOf(i.intValue() + 1)); @@ -137,14 +136,16 @@ public class ComponentGraphics extends CairoGraphics2D */ private void unlock() { - Integer i = (Integer) hasLock.get(); + Integer i = hasLock.get(); if (i == null) throw new IllegalStateException(); if (i == ONE) { - hasLock.set(null); - end_gdk_drawing(); + hasLock.set(null); + end_gdk_drawing(); } + else if (i.intValue() == 2) + hasLock.set(ONE); else hasLock.set(Integer.valueOf(i.intValue() - 1)); } @@ -176,11 +177,11 @@ public class ComponentGraphics extends CairoGraphics2D private static native Pointer nativeGrab(GtkComponentPeer component); private native void copyAreaNative(GtkComponentPeer component, int x, int y, - int width, int height, int dx, int dy); + int width, int height, int dx, int dy); private native void drawVolatile(GtkComponentPeer component, - long vimg, int x, int y, - int width, int height, int cx, int cy, + long vimg, int x, int y, + int width, int height, int cx, int cy, int cw, int ch); /** @@ -232,16 +233,16 @@ public class ComponentGraphics extends CairoGraphics2D { if (comp == null || comp instanceof AlphaComposite) super.draw(s); - + else { createBuffer(); - + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setStroke(this.getStroke()); g2d.setColor(this.getColor()); g2d.draw(s); - + drawComposite(s.getBounds2D(), null); } } @@ -250,16 +251,16 @@ public class ComponentGraphics extends CairoGraphics2D { if (comp == null || comp instanceof AlphaComposite) super.fill(s); - + else { createBuffer(); - + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setPaint(this.getPaint()); g2d.setColor(this.getColor()); g2d.fill(s); - + drawComposite(s.getBounds2D(), null); } } @@ -268,7 +269,7 @@ public class ComponentGraphics extends CairoGraphics2D { if (comp == null || comp instanceof AlphaComposite) super.drawRenderedImage(image, xform); - + else { createBuffer(); @@ -276,7 +277,7 @@ public class ComponentGraphics extends CairoGraphics2D Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setRenderingHints(this.getRenderingHints()); g2d.drawRenderedImage(image, xform); - + drawComposite(buffer.getRaster().getBounds(), null); } } @@ -287,7 +288,7 @@ public class ComponentGraphics extends CairoGraphics2D boolean rv; if (comp == null || comp instanceof AlphaComposite) rv = super.drawImage(img, xform, bgcolor, obs); - + else { // Get buffered image of source @@ -299,7 +300,7 @@ public class ComponentGraphics extends CairoGraphics2D img = Toolkit.getDefaultToolkit().createImage(source); } BufferedImage bImg = (BufferedImage) img; - + // Find translated bounds Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(), @@ -309,18 +310,18 @@ public class ComponentGraphics extends CairoGraphics2D origin = xform.transform(origin, origin); pt = xform.transform(pt, pt); } - + // Create buffer and draw image createBuffer(); - + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); g2d.setRenderingHints(this.getRenderingHints()); g2d.drawImage(img, xform, obs); // Perform compositing rv = drawComposite(new Rectangle2D.Double(origin.getX(), - origin.getY(), - pt.getX(), pt.getY()), + origin.getY(), + pt.getX(), pt.getY()), obs); } return rv; @@ -330,7 +331,7 @@ public class ComponentGraphics extends CairoGraphics2D { if (comp == null || comp instanceof AlphaComposite) super.drawGlyphVector(gv, x, y); - + else { createBuffer(); @@ -339,7 +340,7 @@ public class ComponentGraphics extends CairoGraphics2D g2d.setPaint(this.getPaint()); g2d.setStroke(this.getStroke()); g2d.drawGlyphVector(gv, x, y); - + Rectangle2D bounds = gv.getLogicalBounds(); bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), bounds.getWidth(), bounds.getHeight()); @@ -373,8 +374,8 @@ public class ComponentGraphics extends CairoGraphics2D (int) r.getHeight()); return true; } - else - return super.drawImage(vimg.getSnapshot(), x, y, observer); + else + return super.drawImage(vimg.getSnapshot(), x, y, observer); } BufferedImage bimg; @@ -382,7 +383,7 @@ public class ComponentGraphics extends CairoGraphics2D bimg = (BufferedImage) img; else { - ImageProducer source = img.getSource(); + ImageProducer source = img.getSource(); if (source == null) return false; bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); @@ -418,9 +419,9 @@ public class ComponentGraphics extends CairoGraphics2D (int) r.getHeight()); return true; } - else - return super.drawImage(vimg.getSnapshot(), x, y, - width, height, observer); + else + return super.drawImage(vimg.getSnapshot(), x, y, + width, height, observer); } BufferedImage bimg; @@ -429,7 +430,7 @@ public class ComponentGraphics extends CairoGraphics2D bimg = (BufferedImage) img; else { - ImageProducer source = img.getSource(); + ImageProducer source = img.getSource(); if (source == null) return false; bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); @@ -458,8 +459,8 @@ public class ComponentGraphics extends CairoGraphics2D transform.transform(points, 0, points, 0, 2); Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], - points[2] - points[0], - points[3] - points[1]); + points[2] - points[0], + points[3] - points[1]); Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); @@ -519,8 +520,8 @@ public class ComponentGraphics extends CairoGraphics2D new Point(0,0)); componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, - GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), - new Hashtable()); + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); } } @@ -723,7 +724,7 @@ public class ComponentGraphics extends CairoGraphics2D unlock(); } } - + @Override protected void cairoRectangle(long pointer, double x, double y, double width, double height) @@ -908,4 +909,33 @@ public class ComponentGraphics extends CairoGraphics2D unlock(); } } + + @Override + protected void cairoSetAntialias(long pointer, boolean aa) + { + try + { + lock(); + super.cairoSetAntialias(pointer, aa); + } + finally + { + unlock(); + } + } + + @Override + protected void drawCairoSurface(CairoSurface surface, AffineTransform tx, + double alpha, int interpolation) + { + try + { + lock(); + super.drawCairoSurface(surface, tx, alpha, interpolation); + } + finally + { + unlock(); + } + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java index 131a964488f..280f3e6fbcd 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java @@ -79,6 +79,11 @@ public class FreetypeGlyphVector extends GlyphVector * The glyph codes */ private int[] glyphCodes; + + /** + * The set of fonts used in this glyph vector. + */ + private long[] fontSet = null; /** * Glyph transforms. (de facto only the translation is used) @@ -86,6 +91,19 @@ public class FreetypeGlyphVector extends GlyphVector private AffineTransform[] glyphTransforms; private GlyphMetrics[] metricsCache; + + private native void dispose(long[] fonts); + + /** + * Returns a pointer to the native PangoFcFont object. + * + * The object will be referenced with g_object_ref n times before being + * returned, and must be unreferenced a corresponding number of times. + * + * @param n Number of times to reference the object. + * @return Pointer to the native default font. + */ + private native long getNativeFontPointer(int n); /** * Create a glyphvector from a given (Freetype) font and a String. @@ -112,11 +130,11 @@ public class FreetypeGlyphVector extends GlyphVector getGlyphs(); if( flags == Font.LAYOUT_RIGHT_TO_LEFT ) { - // reverse the glyph ordering. - int[] temp = new int[ nGlyphs ]; - for(int i = 0; i < nGlyphs; i++) - temp[ i ] = glyphCodes[ nGlyphs - i - 1]; - glyphCodes = temp; + // reverse the glyph ordering. + int[] temp = new int[ nGlyphs ]; + for(int i = 0; i < nGlyphs; i++) + temp[i] = glyphCodes[nGlyphs - i - 1]; + glyphCodes = temp; } performDefaultLayout(); } @@ -135,6 +153,13 @@ public class FreetypeGlyphVector extends GlyphVector glyphCodes = new int[ codes.length ]; System.arraycopy(codes, 0, glyphCodes, 0, codes.length); nGlyphs = glyphCodes.length; + + if (fontSet == null) + { + fontSet = new long[nGlyphs]; + Arrays.fill(fontSet, getNativeFontPointer(nGlyphs)); + } + performDefaultLayout(); } @@ -152,11 +177,12 @@ public class FreetypeGlyphVector extends GlyphVector if( gv.metricsCache != null ) { - metricsCache = new GlyphMetrics[ nGlyphs ]; - System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs); + metricsCache = new GlyphMetrics[ nGlyphs ]; + System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs); } glyphCodes = new int[ nGlyphs ]; + fontSet = new long[nGlyphs]; glyphPositions = new float[(nGlyphs + 1) * 2]; glyphTransforms = new AffineTransform[ nGlyphs ]; for(int i = 0; i < nGlyphs; i++ ) @@ -166,6 +192,13 @@ public class FreetypeGlyphVector extends GlyphVector } System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0, glyphPositions.length); + System.arraycopy(gv.glyphCodes, 0, glyphCodes, 0, nGlyphs); + System.arraycopy(gv.fontSet, 0, fontSet, 0, nGlyphs); + } + + public void finalize() + { + dispose(fontSet); } /** @@ -175,16 +208,17 @@ public class FreetypeGlyphVector extends GlyphVector { nGlyphs = s.codePointCount( 0, s.length() ); glyphCodes = new int[ nGlyphs ]; + fontSet = new long[ nGlyphs ]; int[] codePoints = new int[ nGlyphs ]; int stringIndex = 0; for(int i = 0; i < nGlyphs; i++) { - codePoints[i] = s.codePointAt( stringIndex ); + codePoints[i] = s.codePointAt( stringIndex ); // UTF32 surrogate handling - if( codePoints[i] != (int)s.charAt( stringIndex ) ) - stringIndex ++; - stringIndex ++; + if( codePoints[i] != (int)s.charAt( stringIndex ) ) + stringIndex ++; + stringIndex ++; if (Character.isISOControl(codePoints[i])) { @@ -194,22 +228,22 @@ public class FreetypeGlyphVector extends GlyphVector } } - glyphCodes = getGlyphs( codePoints ); + getGlyphs( codePoints, glyphCodes, fontSet ); } /** * Returns the glyph code within the font for a given character */ - public native int[] getGlyphs(int[] codepoints); + public native void getGlyphs(int[] codepoints, int[] glyphs, long[] fonts); /** * Returns the kerning of a glyph pair */ - private native Point2D getKerning(int leftGlyph, int rightGlyph); + private native Point2D getKerning(int leftGlyph, int rightGlyph, long font); - private native double[] getMetricsNative( int glyphCode ); + private native double[] getMetricsNative(int glyphCode, long font); - private native GeneralPath getGlyphOutlineNative(int glyphIndex); + private native GeneralPath getGlyphOutlineNative(int glyphIndex, long font); public Object clone() @@ -267,10 +301,12 @@ public class FreetypeGlyphVector extends GlyphVector x += gm.getAdvanceX(); y += gm.getAdvanceY(); - - if (i != nGlyphs-1) + + // Get the kerning only if it's not the last glyph, and the two glyphs are + // using the same font + if (i != nGlyphs-1 && fontSet[i] == fontSet[i+1]) { - Point2D p = getKerning(glyphCodes[i], glyphCodes[i + 1]); + Point2D p = getKerning(glyphCodes[i], glyphCodes[i + 1], fontSet[i]); x += p.getX(); y += p.getY(); } @@ -291,7 +327,7 @@ public class FreetypeGlyphVector extends GlyphVector * Returns multiple glyphcodes. */ public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, - int[] codeReturn) + int[] codeReturn) { int[] rval; @@ -305,6 +341,26 @@ public class FreetypeGlyphVector extends GlyphVector return rval; } + /** + * Returns pointers to the fonts used in this glyph vector. + * + * The array index matches that of the glyph vector itself. + */ + protected long[] getGlyphFonts(int beginGlyphIndex, int numEntries, + long[] codeReturn) + { + long[] rval; + + if( codeReturn == null || codeReturn.length < numEntries) + rval = new long[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(fontSet, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + public Shape getGlyphLogicalBounds(int glyphIndex) { GlyphMetrics gm = getGlyphMetrics( glyphIndex ); @@ -335,26 +391,24 @@ public class FreetypeGlyphVector extends GlyphVector for(int i = 0; i < nGlyphs; i++) { - GlyphMetrics gm = (GlyphMetrics) - peer.getGlyphMetrics( glyphCodes[ i ] ); - if( gm == null ) - { - double[] val = getMetricsNative( glyphCodes[ i ] ); - if( val == null ) - gm = null; - else - { - gm = new GlyphMetrics( true, - (float)val[1], - (float)val[2], - new Rectangle2D.Double - ( val[3], val[4], - val[5], val[6] ), - GlyphMetrics.STANDARD ); - peer.putGlyphMetrics( glyphCodes[ i ], gm ); - } - } - metricsCache[ i ] = gm; + GlyphMetrics gm = (GlyphMetrics)peer.getGlyphMetrics(glyphCodes[i]); + if( gm == null ) + { + double[] val = getMetricsNative(glyphCodes[i], fontSet[i]); + if( val == null ) + gm = null; + else + { + gm = new GlyphMetrics(true, + (float)val[1], + (float)val[2], + new Rectangle2D.Double(val[3], val[4], + val[5], val[6] ), + GlyphMetrics.STANDARD ); + peer.putGlyphMetrics( glyphCodes[ i ], gm ); + } + } + metricsCache[ i ] = gm; } } @@ -371,13 +425,21 @@ public class FreetypeGlyphVector extends GlyphVector /** * Returns the outline of a single glyph. + * + * Despite what the Sun API says, this method returns the glyph relative to + * the origin of the *entire string*, not each individual glyph. */ public Shape getGlyphOutline(int glyphIndex) { - GeneralPath gp = getGlyphOutlineNative( glyphCodes[ glyphIndex ] ); - if (glyphTransforms[glyphIndex] != null) - gp.transform( glyphTransforms[glyphIndex]); + GeneralPath gp = getGlyphOutlineNative(glyphCodes[glyphIndex], + fontSet[glyphIndex]); + AffineTransform tx = AffineTransform.getTranslateInstance(glyphPositions[glyphIndex*2], + glyphPositions[glyphIndex*2+1]); + if (glyphTransforms[glyphIndex] != null) + tx.concatenate( glyphTransforms[glyphIndex]); + + gp.transform(tx); return gp; } @@ -432,7 +494,6 @@ public class FreetypeGlyphVector extends GlyphVector return logicalBounds; Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 ); - AffineTransform tx = new AffineTransform(); for( int i = 1; i < nGlyphs; i++ ) { Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i ); @@ -458,14 +519,8 @@ public class FreetypeGlyphVector extends GlyphVector public Shape getOutline() { GeneralPath path = new GeneralPath(); - AffineTransform tx = new AffineTransform(); for( int i = 0; i < getNumGlyphs(); i++ ) - { - Shape outline = getGlyphOutline(i); - tx.setToTranslation(glyphPositions[i*2], glyphPositions[i*2 +1]); - outline = tx.createTransformedShape(outline); - path.append(outline, false); - } + path.append(getGlyphOutline(i), false); return path; } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GThreadMutex.java b/libjava/classpath/gnu/java/awt/peer/gtk/GThreadMutex.java deleted file mode 100644 index e73df9e5509..00000000000 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GThreadMutex.java +++ /dev/null @@ -1,109 +0,0 @@ -/* GThreadMutex.java -- Implements a mutex object for glib's gthread - abstraction, for use with GNU Classpath's --portable-native-sync option. - This is used in gthread-jni.c - - 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.awt.peer.gtk; - -/** Implements a mutex object for glib's gthread - abstraction, for use with GNU Classpath's --portable-native-sync option. - This is used in gthread-jni.c. - - We use this object to implement the POSIX semantics for Mutexes. They are - needed are needed for the function vector that is passed to glib's - g_thread subpackage's initialization function. - - The GThreadMutex object itself serves as the Real Lock; if code has - entered the monitor for this GThreadMutex object (in Java language, if - it's synchronized on this object) then it holds the lock that this object - represents. - - @author Steven Augart - May, 2004 - - -*/ - -class GThreadMutex -{ - /** Might "lock" be locked? Is anyone waiting - to get that lock? How long is the queue? - - If zero, nobody holds a lock on this GThreadMutex object, and nobody is - trying to get one. Before someone attempts to acquire a lock on this - object, they must increment potentialLockers. After they release their - lock on this object, they must decrement potentialLockers. - - Access to this field is guarded by synchronizing on the object - <code>lockForPotentialLockers</code>. - - After construction, we only access this field via JNI. - */ - volatile int potentialLockers; - - /** An object to synchronize to if you want to examine or modify the - <code>potentialLockers</code> field. Only hold this lock for brief - moments, just long enough to check or set the value of - <code>lockForPotentialLockers</code>. - - We use this representation so that g_thread_mutex_trylock() will work - with the POSIX semantics. This is the only case in which you ever hold a - lock on <code>lockForPotentialLockers</code> while trying to get another - lock -- if you are the mutex_trylock() implementation, and you have just - checked that <code>potentialLockers</code> has the value zero. In that - case, mutex_trylock() holds the lock on lockForPotentialLockers so that - another thread calling mutex_trylock() or mutex_lock() won't increment - potentialLockers after we've checked it and before we've gained the lock - on the POSIX mutex. Of course, in that case the operation of gaining - the POSIX lock itself will succeed immediately, and once it has - succeeded, trylock releases lockForPotentialLockers right away, - incremented to 1 (one). - - After construction, we only access this field via JNI. - */ - Object lockForPotentialLockers; - - GThreadMutex() - { - potentialLockers = 0; - lockForPotentialLockers = new Object(); - } -} -// Local Variables: -// c-file-style: "gnu" -// End: diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java b/libjava/classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java deleted file mode 100644 index 9a1b8e3a30a..00000000000 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GThreadNativeMethodRunner.java +++ /dev/null @@ -1,303 +0,0 @@ -/* GThreadNativeMethodRunner.java -- Implements pthread_create(), under - glib's gthread abstraction, for use with GNU Classpath's - --portable-native-sync option. - This is used by gthread-jni.c - - Copyright (C) 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 java.lang.ref.WeakReference; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** Implements pthread_create(), under glib's gthread abstraction, for use - with GNU Classpath's --portable-native-sync option. This is used in - gthread-jni.c - - Also implements a registry for threads, mapping Thread objects to small - integers. The registry uses weak references for threads that aren't - joinable, so that they will be garbage collected. - - There are a number of possible alternative implementations. - - - The rest of this comment consists of an answer to a question that was - raised on the commit-classpath mailing list: - - Mark Wielaard wrote: - - > Can't we assume that jobject and gpointer are both (void *) so we don't - > need the int <-> Thread (global jobject ref) mapping? - > Maybe there are platforms where jobject and gpointer aren't the same, - > but I guess that is pretty unlikely. - - - I agree with you on the pointer size issues. A gpointer is a void *, so - it's certainly guaranteed to be at least as large as any other - pointer. And a jobject is implicitly an opaque pointer (in Jikes RVM, we - use small integers, but we coerce them into the representation of a - pointer). - - The int <==> Thread mapping addresses a different issue. I realize that I - did not document this properly (two and a half lines in thread_create), - and the point is subtle (at least to me; took me a while to figure out). - - The int => Thread mapping always returns jobjects that are local - references, not global ones. This is because Thread objects need to be - able to go away and be garbage collected after the thread they refer to - has died. - - If we keep a global object reference to a thread, then when do we delete - that global object reference? We have an answer in the case of GThread - objects that were explicitly created with the joinable attribute. It is - safe for us to maintain a global reference to any joinable thread, since - the joinable thread must linger (even if only in a zombie state) - until it's explicitly joined via a g_thread_join() call. The global ref - could be cleaned up at that point too. - - However, in the case of GThreads that were created non-joinable by - g_thread_create(), and in the case of Java threads that were created - within pure Java code (not via g_thread_create()), we don't want them to - linger forever, and there is no way to tell when the last reference - to such threads needs to expire. In the case of this application -- AWT - with GTK peers -- it would probably be safe anyway, since there are not - very many threads we create, but I was going for correctness even in the - case of long-running programs that might set up and tear down AWT - interfaces many times. - - So, I duplicated the POSIX thread-ID semantics. The thread ID of a - non-joinable thread remains valid as long as that thread is still alive. - Once that thread dies, the old thread ID may be reused at any moment. And - that's why the array indexed by thread ID numbers is an array of weak - references. - - That's also why the int => Thread jobject mapping function always returns - local references, since global references would lock the Thread in memory - forever. - - I would dearly love there to be a cleaner solution. I dislike the - repeated dips from C code into Java that are necessary to look up thread - ID numbers. If anyone can think of one, I'm all ears. -*/ - -class GThreadNativeMethodRunner - extends Thread -{ - /** The C function pointer that was passed to g_thread_create(). - Specifically, this the numeric address of an object of - C type "void *(*funcPtr)(void *funcArg)". - */ - private final long funcPtr; - - /** The argument for the function "funcPtr(funcArg)". */ - private final long funcArg; - - GThreadNativeMethodRunner(long funcPtr, long funcArg, boolean joinable) - { - this.funcPtr = funcPtr; - this.funcArg = funcArg; - - if (joinable) - registerSelfJoinable(); - } - - public void run() - { - nativeRun(funcPtr, funcArg); - } - - private native void nativeRun(long funcPtr, long funcArg); - - /** THREADS is an array of threads, indexed by thread ID codes. Not sure - whether this is the "best" approach but it does make it O(1) to look up a - thread by its ID. - - Zero is a valid thread ID code. Any negative number is invalid. - - Possible future fixes (TODO?) - - - The THREADS array will only grow. probably not a problem. - But we could keep count when nulling entries and shrink when we have - lots of nulls at the end. Probably not worth it. --mjw - - - Could make this a set of Object; see the comment on "joinable" below. - - The initial size of 17 is just a starting point. Any number will do, - including zero. - */ - private static WeakReference[] threads = new WeakReference[17]; - - /** Used by threadToThreadID, below. Returns the registration number of - the newly-registered thread. - */ - private static synchronized int registerThread(Thread t) - { - int i; - - for (i = 0; i < threads.length; ++i) - { - WeakReference ref = threads[i]; - if (ref == null) - break; // found an empty spot. - } - - if (i == threads.length) - { - /* expand the array */ - WeakReference[] bigger = new WeakReference[threads.length * 2]; - System.arraycopy(threads, 0, bigger, 0, threads.length); - threads = bigger; - } - - threads[i] = new WeakReference(t); - - return i; - } - - /** Look up the Thread ID # for a Thread. Assign a Thread ID # if none - exists. This is a general routine for handling all threads, including - the VM's main thread, if appropriate. - - - Runs in O(n/2) time. - - We can't just issue a threadID upon thread creation. If we were to do - that, not all threads would have a threadID, because not all threads - are launched by GThreadNativeMethodRunner. - */ - static synchronized int threadToThreadID(Thread t) - { - for (int i = 0; i < threads.length; ++i ) - { - if (threads[i] == null) - continue; - Thread referent = (Thread) threads[i].get(); - if (referent == null) - { - threads[i] = null; // Purge the dead WeakReference. - continue; - } - if (referent.equals(t)) - return i; - } // for() - - /* No match found. */ - return registerThread(t); - } - - /** @param threadID Must be a non-negative integer. - - Used to return null if the thread number was out of range or if - the thread was unregistered. Now we throw an exception. - - Possible Alternative Interface: We could go back to returning null in - some sort of check-free mode, so code that calls this function must - be prepared to get null. - */ - static Thread threadIDToThread(int threadID) - throws IllegalArgumentException - { - if (threadID < 0) - throw new IllegalArgumentException("Received a negative threadID, " - + threadID); - if (threadID >= threads.length) - throw new IllegalArgumentException("Received a threadID (" + threadID - + ") higher than was" - + " ever issued"); - - /* Note: if the user is using a stale reference, things will just - break. We might end up getting a different thread than the one - expected. - - TODO: Add an error-checking mode where the user's problems with threads - are announced. For instance, if the user asks for the thread - associated with a threadID that was never issued, we could print a - warning or even abort. - - TODO: Consider optionally disabling all of the error-checking we - already have; it probably slows down the implementation. We could - just return NULL. This is just the reverse of the above TODO item. - */ - - WeakReference threadRef = threads[threadID]; - - if (threadRef == null) - throw new IllegalArgumentException("Asked to look up a stale or unissued" - + "threadID (" + threadID + ")" ); - - - Thread referent = (Thread) threadRef.get(); - if (referent == null) - throw new IllegalArgumentException ("Asked to look up a stale threadID (" - + threadID + ")"); - return referent; - } - - /** Joinable threads need a hard reference, so that they won't go away when - they die. That is because their thread IDs need to stay valid until the - thread is joined via thread_join(threadID). Joinable threads have to be - explicitly joined before they are allowed to go away completely. - - Possible Alternative Implementation: Eliminate the Joinable set. When - calling getThreadIDFromThread() you know whether or not the thread - is joinable. So just store the Thread itself in the threads array? - Make that array an Object array and check with instanceof. This - looks cleaner and more robust to me and it saves a native -> Java - call. But instanceof might be expensive. --mjw - */ - private static final Set joinable = - Collections.synchronizedSet(new HashSet()); - - /** Only called from the constructor. */ - private void registerSelfJoinable() - { - joinable.add(this); - } - - /** This method is only called from JNI, and only after we have succeeded in - a thread_join() operation. */ - static void deRegisterJoinable(Thread thread) - { - joinable.remove(thread); - } -} - -// Local Variables: -// c-file-style: "gnu" -// End: diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java index 5f5126ac590..c3c94d8a935 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java @@ -67,7 +67,7 @@ public class GdkFontPeer extends ClasspathFontPeer * The size of the cache has been chosen so that relativly large GUIs with * text documents are still efficient. */ - HashMap textLayoutCache = new GtkToolkit.LRUCache(500); + HashMap<String,TextLayout> textLayoutCache = new GtkToolkit.LRUCache<String,TextLayout>(500); private class GdkFontMetrics extends FontMetrics { @@ -79,7 +79,7 @@ public class GdkFontPeer extends ClasspathFontPeer public int stringWidth (String str) { - TextLayout tl = (TextLayout) textLayoutCache.get(str); + TextLayout tl = textLayoutCache.get(str); if (tl == null) { tl = new TextLayout(str, font, DEFAULT_CTX); @@ -140,7 +140,7 @@ public class GdkFontPeer extends ClasspathFontPeer /** * Cache GlyphMetrics objects. */ - private HashMap metricsCache; + private HashMap<Integer,GlyphMetrics> metricsCache; private static final int FONT_METRICS_ASCENT = 0; private static final int FONT_METRICS_MAX_ASCENT = 1; @@ -235,7 +235,7 @@ public class GdkFontPeer extends ClasspathFontPeer super(name, style, size); initState (); setFont (this.familyName, this.style, (int)this.size); - metricsCache = new HashMap(); + metricsCache = new HashMap<Integer,GlyphMetrics>(); setupMetrics(); } @@ -244,7 +244,7 @@ public class GdkFontPeer extends ClasspathFontPeer super(name, attributes); initState (); setFont (this.familyName, this.style, (int)this.size); - metricsCache = new HashMap(); + metricsCache = new HashMap<Integer,GlyphMetrics>(); setupMetrics(); } @@ -261,9 +261,9 @@ public class GdkFontPeer extends ClasspathFontPeer return font; else { - ClasspathToolkit toolkit; - toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit(); - return toolkit.getFont(font.getName(), font.getAttributes()); + ClasspathToolkit toolkit; + toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit(); + return toolkit.getFont(font.getName(), font.getAttributes()); } } @@ -294,9 +294,9 @@ public class GdkFontPeer extends ClasspathFontPeer name = getName(NameDecoder.NAME_SUBFAMILY, locale); if (name == null) { - name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH); - if ("Regular".equals(name)) - name = null; + name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH); + if ("Regular".equals(name)) + name = null; } return name; @@ -340,12 +340,12 @@ public class GdkFontPeer extends ClasspathFontPeer { if (nameTable == null) { - byte[] data = getTrueTypeTable((byte)'n', (byte) 'a', - (byte) 'm', (byte) 'e'); - if( data == null ) - return null; + byte[] data = getTrueTypeTable((byte)'n', (byte) 'a', + (byte) 'm', (byte) 'e'); + if( data == null ) + return null; - nameTable = ByteBuffer.wrap( data ); + nameTable = ByteBuffer.wrap( data ); } return NameDecoder.getName(nameTable, name, locale); @@ -492,8 +492,8 @@ public class GdkFontPeer extends ClasspathFontPeer char[] chars, int start, int limit, int flags) { - return new FreetypeGlyphVector( font, chars, start, limit - start, - frc, flags); + return new FreetypeGlyphVector(font, chars, start, limit - start, + frc, flags); } public LineMetrics getLineMetrics (Font font, String str, @@ -515,13 +515,13 @@ public class GdkFontPeer extends ClasspathFontPeer */ GlyphMetrics getGlyphMetrics( int glyphCode ) { - return (GlyphMetrics)metricsCache.get( new Integer( glyphCode ) ); + return metricsCache.get(new Integer(glyphCode)); } /** * Put a GlyphMetrics object in the cache. */ - void putGlyphMetrics( int glyphCode, Object metrics ) + void putGlyphMetrics( int glyphCode, GlyphMetrics metrics ) { metricsCache.put( new Integer( glyphCode ), metrics ); } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java index db725b697df..bd6daa2d1e5 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -38,16 +38,21 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import gnu.java.awt.ClasspathGraphicsEnvironment; + import java.awt.Font; import java.awt.Graphics2D; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; import java.util.Locale; -public class GdkGraphicsEnvironment extends GraphicsEnvironment +public class GdkGraphicsEnvironment extends ClasspathGraphicsEnvironment { private final int native_state = GtkGenericPeer.getUniqueInteger (); @@ -139,4 +144,13 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment * Used by GtkMouseInfoPeer. */ native int[] getMouseCoordinates(); + + public WritableRaster createRaster(ColorModel cm, SampleModel sm) + { + if (CairoSurface.isCompatibleSampleModel(sm) + && CairoSurface.isCompatibleColorModel(cm)) + return new CairoSurface(sm.getWidth(), sm.getHeight()); + else + return null; + } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java index 6d0a52b91be..6f6ea560db7 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -184,22 +184,22 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder int len = 0; synchronized(pixbufLock) { - initState(); + initState(); } needsClose = true; // Note: We don't want the pixbufLock while reading from the InputStream. while ((len = is.read (bytes)) != -1) { - synchronized(pixbufLock) - { - pumpBytes (bytes, len); - } + synchronized(pixbufLock) + { + pumpBytes (bytes, len); + } } synchronized(pixbufLock) { - pumpDone(); + pumpDone(); } needsClose = false; @@ -217,7 +217,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder { synchronized(pixbufLock) { - finish(needsClose); + finish(needsClose); } } @@ -226,8 +226,8 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder { public String name; public boolean writable = false; - public ArrayList mimeTypes = new ArrayList(); - public ArrayList extensions = new ArrayList(); + public ArrayList<String> mimeTypes = new ArrayList<String>(); + public ArrayList<String> extensions = new ArrayList<String>(); public ImageFormatSpec(String name, boolean writable) { @@ -246,7 +246,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder } } - static ArrayList imageFormatSpecs; + static ArrayList<ImageFormatSpec> imageFormatSpecs; public static ImageFormatSpec registerFormat(String name, boolean writable) { @@ -254,7 +254,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder synchronized(GdkPixbufDecoder.class) { if (imageFormatSpecs == null) - imageFormatSpecs = new ArrayList(); + imageFormatSpecs = new ArrayList<ImageFormatSpec>(); imageFormatSpecs.add(ifs); } return ifs; @@ -262,13 +262,13 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder static String[] getFormatNames(boolean writable) { - ArrayList names = new ArrayList(); + ArrayList<String> names = new ArrayList<String>(); synchronized (imageFormatSpecs) { - Iterator i = imageFormatSpecs.iterator(); + Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator(); while (i.hasNext()) { - ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + ImageFormatSpec ifs = i.next(); if (writable && !ifs.writable) continue; names.add(ifs.name); @@ -279,62 +279,50 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder * This generally means "all the extensions people might use". */ - Iterator j = ifs.extensions.iterator(); + Iterator<String> j = ifs.extensions.iterator(); while (j.hasNext()) - names.add((String) j.next()); + names.add(j.next()); } } - Object[] objs = names.toArray(); - String[] strings = new String[objs.length]; - for (int i = 0; i < objs.length; ++i) - strings[i] = (String) objs[i]; - return strings; + return names.toArray(new String[names.size()]); } static String[] getFormatExtensions(boolean writable) { - ArrayList extensions = new ArrayList(); + ArrayList<String> extensions = new ArrayList<String>(); synchronized (imageFormatSpecs) { - Iterator i = imageFormatSpecs.iterator(); + Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator(); while (i.hasNext()) { - ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + ImageFormatSpec ifs = i.next(); if (writable && !ifs.writable) continue; - Iterator j = ifs.extensions.iterator(); + Iterator<String> j = ifs.extensions.iterator(); while (j.hasNext()) - extensions.add((String) j.next()); + extensions.add(j.next()); } } - Object[] objs = extensions.toArray(); - String[] strings = new String[objs.length]; - for (int i = 0; i < objs.length; ++i) - strings[i] = (String) objs[i]; - return strings; + return extensions.toArray(new String[extensions.size()]); } static String[] getFormatMimeTypes(boolean writable) { - ArrayList mimeTypes = new ArrayList(); + ArrayList<String> mimeTypes = new ArrayList<String>(); synchronized (imageFormatSpecs) { - Iterator i = imageFormatSpecs.iterator(); + Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator(); while (i.hasNext()) { - ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + ImageFormatSpec ifs = i.next(); if (writable && !ifs.writable) continue; - Iterator j = ifs.mimeTypes.iterator(); + Iterator<String> j = ifs.mimeTypes.iterator(); while (j.hasNext()) - mimeTypes.add((String) j.next()); + mimeTypes.add(j.next()); } } - Object[] objs = mimeTypes.toArray(); - String[] strings = new String[objs.length]; - for (int i = 0; i < objs.length; ++i) - strings[i] = (String) objs[i]; - return strings; + return mimeTypes.toArray(new String[mimeTypes.size()]); } @@ -348,10 +336,10 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder String str = (String) ext; - Iterator i = imageFormatSpecs.iterator(); + Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator(); while (i.hasNext()) { - ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + ImageFormatSpec ifs = i.next(); if (needWritable && !ifs.writable) continue; @@ -359,10 +347,10 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder if (ifs.name.equals(str)) return str; - Iterator j = ifs.extensions.iterator(); + Iterator<String> j = ifs.extensions.iterator(); while (j.hasNext()) { - String extension = (String)j.next(); + String extension = j.next(); if (extension.equals(str)) return ifs.name; } @@ -370,7 +358,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder j = ifs.mimeTypes.iterator(); while (j.hasNext()) { - String mimeType = (String)j.next(); + String mimeType = j.next(); if (mimeType.equals(str)) return ifs.name; } @@ -510,10 +498,10 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder if (pixels == null) { - BufferedImage img; - if(model != null && model.hasAlpha()) - img = CairoSurface.getBufferedImage(width, height); - img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + BufferedImage img; + if(model != null && model.hasAlpha()) + img = CairoSurface.getBufferedImage(width, height); + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); int[] pix = new int[4]; for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) @@ -527,10 +515,10 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder workerThread.start(); processImageStarted(1); synchronized(pixbufLock) - { - streamImage(pixels, this.ext, width, height, model.hasAlpha(), - this); - } + { + streamImage(pixels, this.ext, width, height, model.hasAlpha(), + this); + } synchronized(data) { data.add(DATADONE); @@ -539,18 +527,18 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder while (workerThread.isAlive()) { - try - { - workerThread.join(); - } - catch (InterruptedException ioe) - { - // Ignored. - } + try + { + workerThread.join(); + } + catch (InterruptedException ioe) + { + // Ignored. + } } if (exception != null) - throw exception; + throw exception; processImageComplete(); } @@ -566,7 +554,7 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder * Needs to be synchronized for access. * The special object DATADONE is added when all data has been delivered. */ - private ArrayList data = new ArrayList(); + private ArrayList<Object> data = new ArrayList<Object>(); /** * Holds any IOException thrown by the run method that needs @@ -643,7 +631,8 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder this.ext = findFormatName(ext, false); } - public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, GdkPixbufDecoder d) + public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, + GdkPixbufDecoder d) { this(ownerSpi, ext); dec = d; @@ -680,10 +669,12 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder if (bufferedImage == null) { - if(model != null && model.hasAlpha()) - bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); - else - bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB); + if(model != null && model.hasAlpha()) + bufferedImage = new BufferedImage (width, height, + BufferedImage.TYPE_INT_ARGB); + else + bufferedImage = new BufferedImage (width, height, + BufferedImage.TYPE_INT_RGB); } int pixels2[]; @@ -735,11 +726,11 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder return null; } - public Iterator getImageTypes(int imageIndex) + public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException { BufferedImage img = getBufferedImage(); - Vector vec = new Vector(); + Vector<ImageTypeSpecifier> vec = new Vector<ImageTypeSpecifier>(); vec.add(new ImageTypeSpecifier(img)); return vec.iterator(); } @@ -767,8 +758,8 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder else if (get instanceof DataInput) dec = new GdkPixbufDecoder((DataInput) get); else - throw new IllegalArgumentException("input object not supported: " - + get); + throw new IllegalArgumentException("input object not supported: " + + get); } public BufferedImage read(int imageIndex, ImageReadParam param) diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java index 62116a3226c..a69c6f0659e 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java @@ -188,7 +188,7 @@ class GdkScreenGraphicsDevice extends GraphicsDevice displayModes = nativeGetDisplayModes(env); } - ArrayList list = new ArrayList(); + ArrayList<DisplayMode> list = new ArrayList<DisplayMode>(); for(int i=0;i<displayModes.length;i++) for(int j=0;j<displayModes[i].rates.length;j++) list.add(new DisplayMode(displayModes[i].width, @@ -196,7 +196,7 @@ class GdkScreenGraphicsDevice extends GraphicsDevice DisplayMode.BIT_DEPTH_MULTI, displayModes[i].rates[j])); - return (DisplayMode[]) list.toArray(new DisplayMode[list.size()]); + return list.toArray(new DisplayMode[list.size()]); } native X11DisplayMode[] nativeGetDisplayModes(GdkGraphicsEnvironment env); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java index 90d16c57282..4a41d0696c3 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java @@ -57,7 +57,8 @@ public class GtkCheckboxPeer extends GtkComponentPeer private boolean currentState; // A map from CheckboxGroup to GSList* GTK option group pointer. - private static WeakHashMap groupMap = new WeakHashMap(); + private static WeakHashMap<CheckboxGroup,Long> groupMap + = new WeakHashMap<CheckboxGroup,Long>(); public native void createCheckButton (); public native void createRadioButton (long groupPointer); @@ -98,7 +99,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer Long groupPointer = null; synchronized (groupMap) { - groupPointer = (Long) groupMap.get(current_group); + groupPointer = groupMap.get(current_group); } if (groupPointer == null) @@ -133,8 +134,8 @@ public class GtkCheckboxPeer extends GtkComponentPeer { if (currentState != state) { - currentState = state; - gtkToggleButtonSetActive(state); + currentState = state; + gtkToggleButtonSetActive(state); } } @@ -158,7 +159,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer Long groupPointer = null; synchronized (groupMap) { - groupPointer = (Long) groupMap.get(current_group); + groupPointer = groupMap.get(current_group); } if (groupPointer == null) @@ -203,7 +204,7 @@ public class GtkCheckboxPeer extends GtkComponentPeer Long groupPointer = null; synchronized (groupMap) { - groupPointer = (Long) groupMap.get(current_group); + groupPointer = groupMap.get(current_group); } if (groupPointer == null) @@ -230,9 +231,9 @@ public class GtkCheckboxPeer extends GtkComponentPeer // Only fire event is state actually changed. if (currentState != state) { - currentState = state; - super.postItemEvent(awtComponent, - state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); + currentState = state; + super.postItemEvent(awtComponent, + state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java index d866cefd33c..ff061d35c74 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java @@ -55,12 +55,12 @@ public class GtkChoicePeer extends GtkComponentPeer int count = c.getItemCount (); if (count > 0) { - for (int i = 0; i < count; i++) - add( c.getItem(i), i ); + for (int i = 0; i < count; i++) + add(c.getItem(i), i); - selected = c.getSelectedIndex(); - if( selected >= 0 ) - select( selected ); + selected = c.getSelectedIndex(); + if (selected >= 0) + select( selected ); } else selected = -1; @@ -121,9 +121,9 @@ public class GtkChoicePeer extends GtkComponentPeer { if( selected != index ) { - selected = index; - postItemEvent (((Choice) awtComponent).getItem( selected ), - ItemEvent.SELECTED); + selected = index; + postItemEvent (((Choice) awtComponent).getItem( selected ), + ItemEvent.SELECTED); } } @@ -133,11 +133,11 @@ public class GtkChoicePeer extends GtkComponentPeer */ public void handleEvent (AWTEvent event) { - super.handleEvent( event ); - if( event instanceof ItemEvent ) - if( ((ItemEvent)event).getItemSelectable() == awtComponent && - ((ItemEvent)event).getStateChange() == ItemEvent.SELECTED ) - ((Choice)awtComponent).select( selected ); + super.handleEvent (event); + if (event instanceof ItemEvent) + if (((ItemEvent)event).getItemSelectable() == awtComponent + && ((ItemEvent)event).getStateChange() == ItemEvent.SELECTED) + ((Choice)awtComponent).select( selected ); } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java index f520fe224b1..e41754641bb 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java @@ -71,9 +71,9 @@ public class GtkClipboard extends Clipboard // cached by GtkSelection. True if // gdk_display_supports_selection_notification. static final boolean canCache = initNativeState(clipboard, selection, - stringMimeType, - imageMimeType, - filesMimeType); + stringMimeType, + imageMimeType, + filesMimeType); /** * Creates the clipboard and sets the initial contents to the @@ -140,8 +140,8 @@ public class GtkClipboard extends Clipboard if (contents == null) { - advertiseContent(null, false, false, false); - return; + advertiseContent(null, false, false, false); + return; } // We don't need to do anything for a GtkSelection facade. @@ -153,46 +153,45 @@ public class GtkClipboard extends Clipboard boolean files = false; if (contents instanceof StringSelection - || contents.isDataFlavorSupported(DataFlavor.stringFlavor) - || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor) - || contents.isDataFlavorSupported(DataFlavor - .getTextPlainUnicodeFlavor())) + || contents.isDataFlavorSupported(DataFlavor.stringFlavor) + || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor) + || contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())) text = true; DataFlavor[] flavors = contents.getTransferDataFlavors(); String[] mimeTargets = new String[flavors.length]; for (int i = 0; i < flavors.length; i++) { - DataFlavor flavor = flavors[i]; - String mimeType = flavor.getMimeType(); - mimeTargets[i] = mimeType; - - if (! text) - if ("text".equals(flavor.getPrimaryType()) - || flavor.isRepresentationClassReader()) - text = true; - - if (! images && flavors[i].equals(DataFlavor.imageFlavor)) - { - try - { - Object o = contents.getTransferData(DataFlavor.imageFlavor); - if (o instanceof Image) - images = true; - } - catch (UnsupportedFlavorException ufe) - { - } - catch (IOException ioe) - { - } - catch (ClassCastException cce) - { - } - } - - if (flavors[i].equals(DataFlavor.javaFileListFlavor)) - files = true; + DataFlavor flavor = flavors[i]; + String mimeType = flavor.getMimeType(); + mimeTargets[i] = mimeType; + + if (! text) + if ("text".equals(flavor.getPrimaryType()) + || flavor.isRepresentationClassReader()) + text = true; + + if (! images && flavors[i].equals(DataFlavor.imageFlavor)) + { + try + { + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if (o instanceof Image) + images = true; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + } + + if (flavors[i].equals(DataFlavor.javaFileListFlavor)) + files = true; } advertiseContent(mimeTargets, text, images, files); @@ -207,9 +206,9 @@ public class GtkClipboard extends Clipboard * selection has explicitly been erased. */ private native void advertiseContent(String[] targets, - boolean text, - boolean images, - boolean files); + boolean text, + boolean images, + boolean files); /** * Called by the gtk+ clipboard when an application has requested @@ -228,7 +227,7 @@ public class GtkClipboard extends Clipboard try { return (String) contents.getTransferData(DataFlavor.stringFlavor); - } + } catch (UnsupportedFlavorException ufe) { } @@ -244,20 +243,20 @@ public class GtkClipboard extends Clipboard // turn the result into a string. try { - DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor(); - Reader r = plainText.getReaderForText(contents); - if (r != null) - { - StringBuffer sb = new StringBuffer(); - char[] cs = new char[1024]; - int l = r.read(cs); - while (l != -1) - { - sb.append(cs, 0, l); - l = r.read(cs); - } - return sb.toString(); - } + DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor(); + Reader r = plainText.getReaderForText(contents); + if (r != null) + { + StringBuffer sb = new StringBuffer(); + char[] cs = new char[1024]; + int l = r.read(cs); + while (l != -1) + { + sb.append(cs, 0, l); + l = r.read(cs); + } + return sb.toString(); + } } catch (IllegalArgumentException iae) { @@ -288,11 +287,11 @@ public class GtkClipboard extends Clipboard try { - Object o = contents.getTransferData(DataFlavor.imageFlavor); - if( o instanceof GtkImage ) - return (GtkImage) o; - else - return new GtkImage(((Image)o).getSource()); + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if( o instanceof GtkImage ) + return (GtkImage) o; + else + return new GtkImage(((Image)o).getSource()); } catch (UnsupportedFlavorException ufe) { @@ -321,14 +320,13 @@ public class GtkClipboard extends Clipboard try { - List list = (List) contents.getTransferData - (DataFlavor.javaFileListFlavor); - String[] uris = new String[list.size()]; - int u = 0; - Iterator it = list.iterator(); - while (it.hasNext()) - uris[u++] = ((File) it.next()).toURI().toString(); - return uris; + List list = (List) contents.getTransferData(DataFlavor.javaFileListFlavor); + String[] uris = new String[list.size()]; + int u = 0; + Iterator it = list.iterator(); + while (it.hasNext()) + uris[u++] = ((File) it.next()).toURI().toString(); + return uris; } catch (UnsupportedFlavorException ufe) { @@ -365,34 +363,34 @@ public class GtkClipboard extends Clipboard // the other provideXXX() methods. try { - DataFlavor flavor = new DataFlavor(target); - Object o = contents.getTransferData(flavor); - - if (o instanceof byte[]) - return (byte[]) o; - - if (o instanceof InputStream) - { - InputStream is = (InputStream) o; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] bs = new byte[1024]; - int l = is.read(bs); - while (l != -1) - { - baos.write(bs, 0, l); - l = is.read(bs); - } - return baos.toByteArray(); - } - - if (o instanceof Serializable) - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(o); - oos.close(); - return baos.toByteArray(); - } + DataFlavor flavor = new DataFlavor(target); + Object o = contents.getTransferData(flavor); + + if (o instanceof byte[]) + return (byte[]) o; + + if (o instanceof InputStream) + { + InputStream is = (InputStream) o; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] bs = new byte[1024]; + int l = is.read(bs); + while (l != -1) + { + baos.write(bs, 0, l); + l = is.read(bs); + } + return baos.toByteArray(); + } + + if (o instanceof Serializable) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.close(); + return baos.toByteArray(); + } } catch (ClassNotFoundException cnfe) { @@ -416,8 +414,8 @@ public class GtkClipboard extends Clipboard * Clipboard can be cached (gdk_display_supports_selection_notification). */ private static native boolean initNativeState(GtkClipboard clipboard, - GtkClipboard selection, - String stringTarget, - String imageTarget, - String filesTarget); + GtkClipboard selection, + String stringTarget, + String imageTarget, + String filesTarget); } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java index 61df796dc00..8e593455774 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java @@ -74,11 +74,11 @@ class GtkClipboardNotifier extends Thread { synchronized (notifier) { - if (clipboard == GtkClipboard.clipboard) - announceClipboardChange = true; - else - announcePrimaryChange = true; - notifier.notifyAll(); + if (clipboard == GtkClipboard.clipboard) + announceClipboardChange = true; + else + announcePrimaryChange = true; + notifier.notifyAll(); } } @@ -87,44 +87,43 @@ class GtkClipboardNotifier extends Thread GtkClipboard clipboard; while (true) { - synchronized (this) - { - while (! announceClipboardChange && ! announcePrimaryChange) - { - try - { - this.wait(); - } - catch (InterruptedException ie) - { - // ignore - } - } - - 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(clipboard), null); - } - catch (Throwable t) - { - // should never happen, but might if we have some faulty - // listener. - t.printStackTrace(); - } + synchronized (this) + { + while (! announceClipboardChange && ! announcePrimaryChange) + { + try + { + this.wait(); + } + catch (InterruptedException ie) + { + // ignore + } + } + + 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(clipboard), null); + } + catch (Throwable t) + { + // should never happen, but might if we have some faulty listener. + t.printStackTrace(); + } } } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java index b1ef09d6e1b..a7ae8e17f2b 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -109,7 +109,7 @@ public class GtkComponentPeer extends GtkGenericPeer native void gtkWidgetGetLocationOnScreen (int[] point); native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y); native void gtkWidgetSetCursorUnlocked (int type, GtkImage image, - int x, int y); + 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); @@ -206,7 +206,7 @@ public class GtkComponentPeer extends GtkGenericPeer } public int checkImage (Image image, int width, int height, - ImageObserver observer) + ImageObserver observer) { return getToolkit().checkImage(image, width, height, observer); } @@ -402,7 +402,7 @@ public class GtkComponentPeer extends GtkGenericPeer } public boolean prepareImage (Image image, int width, int height, - ImageObserver observer) + ImageObserver observer) { return getToolkit().prepareImage(image, width, height, observer); } @@ -539,17 +539,17 @@ public class GtkComponentPeer extends GtkGenericPeer 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; + GtkCursor gtkCursor = (GtkCursor) cursor; + image = gtkCursor.getGtkImage(); + Point hotspot = gtkCursor.getHotspot(); + x = hotspot.x; + y = hotspot.y; } else { - image = null; - x = 0; - y = 0; + image = null; + x = 0; + y = 0; } if (Thread.currentThread() == GtkMainThread.mainThread) @@ -597,7 +597,7 @@ public class GtkComponentPeer extends GtkGenericPeer if (b && ! (awtComponent instanceof Window)) { Rectangle bounds = awtComponent.getBounds(); - b = (bounds.width > 0) && (bounds.height > 0); + b = (bounds.width > 0) && (bounds.height > 0); } if (Thread.currentThread() == GtkMainThread.mainThread) @@ -617,23 +617,23 @@ public class GtkComponentPeer extends GtkGenericPeer } protected void postMouseEvent(int id, long when, int mods, int x, int y, - int clickCount, boolean popupTrigger) + int clickCount, boolean popupTrigger) { q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y, - clickCount, popupTrigger)); + 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) + 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)); + x, y, clickCount, popupTrigger, + type, amount, rotation)); } protected void postExposeEvent (int x, int y, int width, int height) @@ -659,12 +659,12 @@ public class GtkComponentPeer extends GtkGenericPeer && keyCode != KeyEvent.VK_ALT)) { synchronized(q) - { - q.postEvent(keyEvent); - keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when, - mods, KeyEvent.VK_UNDEFINED, keyChar, - keyLocation); - q.postEvent(keyEvent); + { + q.postEvent(keyEvent); + keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when, + mods, KeyEvent.VK_UNDEFINED, keyChar, + keyLocation); + q.postEvent(keyEvent); } } else @@ -685,8 +685,8 @@ public class GtkComponentPeer extends GtkGenericPeer protected void postItemEvent (Object item, int stateChange) { q().postEvent (new ItemEvent ((ItemSelectable)awtComponent, - ItemEvent.ITEM_STATE_CHANGED, - item, stateChange)); + ItemEvent.ITEM_STATE_CHANGED, + item, stateChange)); } protected void postTextEvent () @@ -828,8 +828,8 @@ public class GtkComponentPeer extends GtkGenericPeer // buffer and one front buffer. if (numBuffers == 2) backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(), - awtComponent.getHeight(), - caps.getBackBufferCapabilities()); + awtComponent.getHeight(), + caps.getBackBufferCapabilities()); else throw new AWTException("GtkComponentPeer.createBuffers:" + " multi-buffering not supported"); @@ -846,18 +846,18 @@ public class GtkComponentPeer extends GtkGenericPeer public void flip (BufferCapabilities.FlipContents contents) { getGraphics().drawImage(backBuffer, - awtComponent.getWidth(), - awtComponent.getHeight(), - null); + awtComponent.getWidth(), + awtComponent.getHeight(), + null); // create new back buffer and clear it to the background color. if (contents == BufferCapabilities.FlipContents.BACKGROUND) { backBuffer = createVolatileImage(awtComponent.getWidth(), - awtComponent.getHeight()); + awtComponent.getHeight()); backBuffer.getGraphics().clearRect(0, 0, - awtComponent.getWidth(), - awtComponent.getHeight()); + awtComponent.getWidth(), + awtComponent.getHeight()); } // FIXME: support BufferCapabilities.FlipContents.PRIOR } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java index 8650578f70e..7d5ef91de13 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java @@ -40,7 +40,6 @@ 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; @@ -160,7 +159,8 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer in turn call the filter's accept() method and give back the return value. */ // called back by native side: filename_filter_cb - boolean filenameFilterCallback (String fullname) { + boolean filenameFilterCallback (String fullname) + { String filename = fullname.substring(fullname.lastIndexOf(FS) + 1); String dirname = fullname.substring(0, fullname.lastIndexOf(FS)); File dir = new File(dirname); @@ -205,19 +205,19 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer if (sepIndex < 0) { /* This should never happen on Unix (all paths start with '/') */ - currentFile = fileName; + currentFile = fileName; } else { if (fileName.length() > (sepIndex + 1)) - { - String fn = fileName.substring (sepIndex + 1); - currentFile = fn; - } - else - { + { + String fn = fileName.substring (sepIndex + 1); + currentFile = fn; + } + else + { currentFile = null; - } + } String dn = fileName.substring (0, sepIndex + 1); currentDirectory = dn; diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java index d113e92f5b4..b35be522746 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java @@ -1,5 +1,5 @@ /* GtkFramePeer.java -- Implements FramePeer with GTK - Copyright (C) 1999, 2002, 2004, 2006 Free Software Foundation, Inc. + Copyright (C) 1999, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -176,13 +176,17 @@ public class GtkFramePeer extends GtkWindowPeer public void setIconImage (Image image) { - if (image != null) - { - if (image instanceof GtkImage) - nativeSetIconImage((GtkImage) image); - else - nativeSetIconImage(new GtkImage(image.getSource())); - } + if (image != null) + { + GtkImage gtkImage; + if (image instanceof GtkImage) + gtkImage = (GtkImage) image; + else + gtkImage = new GtkImage(image.getSource()); + + if (gtkImage.isLoaded && ! gtkImage.errorLoading) + nativeSetIconImage(gtkImage); + } } protected void postConfigureEvent (int x, int y, int width, int height) diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java index 0fd98bbd7b4..719669eae0d 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java @@ -71,7 +71,7 @@ public class GtkImage extends Image /** * Properties. */ - Hashtable props; + Hashtable<?,?> props; /** * Loaded or not flag, for asynchronous compatibility. @@ -87,7 +87,7 @@ public class GtkImage extends Image /** * Observer queue. */ - Vector observers; + Vector<ImageObserver> observers; /** * Error flag for loading. @@ -103,10 +103,10 @@ public class GtkImage extends Image * The 32-bit AABBGGRR format the GDK uses. */ static ColorModel nativeModel = new DirectColorModel(32, - 0x000000FF, - 0x0000FF00, - 0x00FF0000, - 0xFF000000); + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); /** * The singleton GtkImage that is returned on errors by GtkToolkit. @@ -178,7 +178,7 @@ public class GtkImage extends Image public GtkImage (ImageProducer producer) { isLoaded = false; - observers = new Vector(); + observers = new Vector<ImageObserver>(); source = producer; errorLoading = false; source.startProduction(new GtkImageConsumer(this, source)); @@ -194,7 +194,7 @@ public class GtkImage extends Image { isLoaded = true; observers = null; - props = new Hashtable(); + props = new Hashtable<String,Object>(); errorLoading = false; } @@ -208,26 +208,26 @@ public class GtkImage extends Image File f = new File(filename); try { - String path = f.getCanonicalPath(); - synchronized(pixbufLock) - { - if (loadPixbuf(f.getCanonicalPath()) != true) - throw new IllegalArgumentException("Couldn't load image: " - + filename); - } + String path = f.getCanonicalPath(); + synchronized(pixbufLock) + { + if (loadPixbuf(f.getCanonicalPath()) != true) + throw new IllegalArgumentException("Couldn't load image: " + + filename); + } } catch(IOException e) { - IllegalArgumentException iae; - iae = new IllegalArgumentException("Couldn't load image: " - + filename); - iae.initCause(e); - throw iae; + IllegalArgumentException iae; + iae = new IllegalArgumentException("Couldn't load image: " + + filename); + iae.initCause(e); + throw iae; } isLoaded = true; observers = null; - props = new Hashtable(); + props = new Hashtable<String,Object>(); } /** @@ -240,13 +240,13 @@ public class GtkImage extends Image { synchronized(pixbufLock) { - if (loadImageFromData (data) != true) - throw new IllegalArgumentException ("Couldn't load image."); + if (loadImageFromData (data) != true) + throw new IllegalArgumentException ("Couldn't load image."); } isLoaded = true; observers = null; - props = new Hashtable(); + props = new Hashtable<String,Object>(); errorLoading = false; } @@ -256,7 +256,7 @@ public class GtkImage extends Image public GtkImage (URL url) { isLoaded = false; - observers = new Vector(); + observers = new Vector<ImageObserver>(); errorLoading = false; if( url == null) return; @@ -269,23 +269,23 @@ public class GtkImage extends Image int n = 0; while ((n = bis.read(buf)) != -1) - baos.write(buf, 0, n); + baos.write(buf, 0, n); bis.close(); } catch(IOException e) { - throw new IllegalArgumentException ("Couldn't load image."); + throw new IllegalArgumentException ("Couldn't load image."); } byte[] array = baos.toByteArray(); synchronized(pixbufLock) { - if (loadImageFromData(array) != true) - throw new IllegalArgumentException ("Couldn't load image."); + if (loadImageFromData(array) != true) + throw new IllegalArgumentException ("Couldn't load image."); } isLoaded = true; observers = null; - props = new Hashtable(); + props = new Hashtable<String,Object>(); } /** @@ -295,14 +295,14 @@ public class GtkImage extends Image { this.width = width; this.height = height; - props = new Hashtable(); + props = new Hashtable<String,Object>(); isLoaded = true; observers = null; // Use the GDK scaling method. synchronized(pixbufLock) { - createScaledPixbuf(src, hints); + createScaledPixbuf(src, hints); } } @@ -315,11 +315,11 @@ public class GtkImage extends Image this.pixbuf = pixbuf; synchronized(pixbufLock) { - createFromPixbuf(); + createFromPixbuf(); } isLoaded = true; observers = null; - props = new Hashtable(); + props = new Hashtable<String,Object>(); } /** @@ -331,7 +331,7 @@ public class GtkImage extends Image { this.width = width; this.height = height; - props = new Hashtable(); + props = new Hashtable<String,Object>(); isLoaded = true; observers = null; initFromBuffer( bufferPointer ); @@ -346,8 +346,8 @@ public class GtkImage extends Image { if (errorImage == null) { - errorImage = new GtkImage(); - errorImage.errorLoading = true; + errorImage = new GtkImage(); + errorImage.errorLoading = true; } return errorImage; } @@ -362,25 +362,25 @@ public class GtkImage extends Image * Callback from the image consumer. */ public void setImage(int width, int height, - int[] pixels, Hashtable properties) + int[] pixels, Hashtable<?,?> properties) { this.width = width; this.height = height; - props = (properties != null) ? properties : new Hashtable(); + props = (properties != null) ? properties : new Hashtable<String,Object>(); if (width <= 0 || height <= 0 || pixels == null) { - errorLoading = true; - return; + errorLoading = true; + return; } - isLoaded = true; - deliver(); synchronized(pixbufLock) { - createPixbuf(); - setPixels(pixels); + createPixbuf(); + setPixels(pixels); } + isLoaded = true; + deliver(); } // java.awt.Image methods //////////////////////////////////////////////// @@ -427,7 +427,7 @@ public class GtkImage extends Image return null; } return new MemoryImageSource(width, height, nativeModel, pixels, - 0, width); + 0, width); } /** @@ -436,19 +436,19 @@ public class GtkImage extends Image public Graphics getGraphics () { throw new IllegalAccessError("This method only works for off-screen" - +" Images."); + +" Images."); } /** * Returns a scaled instance of this pixbuf. */ public Image getScaledInstance(int width, - int height, - int hints) + int height, + int hints) { if (width <= 0 || height <= 0) - throw new IllegalArgumentException("Width and height of scaled bitmap"+ - "must be >= 0"); + throw new IllegalArgumentException("Width and height of scaled bitmap" + + "must be >= 0"); return new GtkImage(this, width, height, hints); } @@ -465,13 +465,13 @@ public class GtkImage extends Image { if (isLoaded && source != null) { - observers = new Vector(); - isLoaded = false; - synchronized(pixbufLock) + observers = new Vector<ImageObserver>(); + isLoaded = false; + synchronized(pixbufLock) { freePixbuf(); } - source.startProduction(new GtkImageConsumer(this, source)); + source.startProduction(new GtkImageConsumer(this, source)); } } @@ -479,10 +479,10 @@ public class GtkImage extends Image { if (isLoaded) { - synchronized(pixbufLock) - { - freePixbuf(); - } + synchronized(pixbufLock) + { + freePixbuf(); + } } } @@ -493,10 +493,10 @@ public class GtkImage extends Image { if (addObserver(observer)) { - if (errorLoading == true) - return ImageObserver.ERROR; - else - return 0; + if (errorLoading == true) + return ImageObserver.ERROR; + else + return 0; } return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; @@ -517,8 +517,8 @@ public class GtkImage extends Image if (observers != null) for(int i=0; i < observers.size(); i++) - ((ImageObserver)observers.elementAt(i)). - imageUpdate(this, flags, 0, 0, width, height); + ((ImageObserver)observers.elementAt(i)).imageUpdate(this, flags, 0, 0, + width, height); observers = null; } @@ -531,10 +531,10 @@ public class GtkImage extends Image { if (!isLoaded) { - if(observer != null) - if (!observers.contains (observer)) - observers.addElement (observer); - return true; + if(observer != null) + if (!observers.contains (observer)) + observers.addElement (observer); + return true; } return false; } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java index 53e97bb1a8a..44cfaf9266a 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java @@ -55,7 +55,7 @@ public class GtkImageConsumer implements ImageConsumer { private GtkImage target; private int width, height; - private Hashtable properties; + private Hashtable<?,?> properties; private int[] pixelCache = null; private ImageProducer source; @@ -97,55 +97,55 @@ public class GtkImageConsumer implements ImageConsumer } public synchronized void setPixels (int x, int y, int width, int height, - ColorModel cm, byte[] pixels, - int offset, int scansize) + ColorModel cm, byte[] pixels, + int offset, int scansize) { setPixels (x, y, width, height, cm, convertPixels (pixels), offset, scansize); } public synchronized void setPixels (int x, int y, int width, int height, - ColorModel cm, int[] pixels, - int offset, int scansize) + ColorModel cm, int[] pixels, + int offset, int scansize) { if (pixelCache == null) return; // Not sure this should ever happen. if (cm.equals(GtkImage.nativeModel)) for (int i = 0; i < height; i++) - System.arraycopy (pixels, offset + (i * scansize), - pixelCache, (y + i) * this.width + x, - width); + System.arraycopy (pixels, offset + (i * scansize), + pixelCache, (y + i) * this.width + x, + width); else { - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) - { - for (int i = 0; i < height; i++) - for (int j = 0; j < width; j++) - { - // get in RRGGBBAA and convert to AARRGGBB - int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); - int a = ((pix & 0xFF000000) >> 24) & 0xFF; - int rgb = (pix & 0x00FFFFFF) << 8; - pix = rgb | a; - pixelCache[(y + i) * this.width + x + j] = pix; - } - } - else - { - for (int i = 0; i < height; i++) - for (int j = 0; j < width; j++) - { - // get in AARRGGBB and convert to AABBGGRR - int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); - byte b = (byte)(pix & 0xFF); - byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); - pix &= 0xFF00FF00; - pix |= ((b & 0xFF) << 16); - pix |= (r & 0xFF); - pixelCache[(y + i) * this.width + x + j] = pix; - } - } + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in RRGGBBAA and convert to AARRGGBB + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + int a = ((pix & 0xFF000000) >> 24) & 0xFF; + int rgb = (pix & 0x00FFFFFF) << 8; + pix = rgb | a; + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + else + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in AARRGGBB and convert to AABBGGRR + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + byte b = (byte)(pix & 0xFF); + byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); + pix &= 0xFF00FF00; + pix |= ((b & 0xFF) << 16); + pix |= (r & 0xFF); + pixelCache[(y + i) * this.width + x + j] = pix; + } + } } } @@ -162,7 +162,7 @@ public class GtkImageConsumer implements ImageConsumer return ret; } - public synchronized void setProperties (Hashtable props) + public synchronized void setProperties (Hashtable<?,?> props) { this.properties = props; } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java index 02db90d72bd..76f8e5fe331 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java @@ -90,11 +90,11 @@ public class GtkLabelPeer extends GtkComponentPeer switch (alignment) { case Label.LEFT: - return 0.0f; + return 0.0f; case Label.CENTER: - return 0.5f; + return 0.5f; case Label.RIGHT: - return 1.0f; + return 1.0f; } return 0.0f; diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java index bd6ec0aef75..f943a75d171 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java @@ -148,33 +148,33 @@ public class GtkListPeer extends GtkComponentPeer { // Only generate the ActionEvent on the second click of a // multiple click. - MouseEvent me = (MouseEvent) e; - if (!me.isConsumed () - && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0 - && me.getClickCount() == 2) - { + MouseEvent me = (MouseEvent) e; + if (!me.isConsumed () + && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0 + && me.getClickCount() == 2) + { String selectedItem = ((List) awtComponent).getSelectedItem (); // Double-click only generates an Action event if // something is selected. if (selectedItem != null) - postActionEvent (((List) awtComponent).getSelectedItem (), - me.getModifiersEx ()); - } + postActionEvent (((List) awtComponent).getSelectedItem (), + me.getModifiersEx ()); + } } if (e.getID () == KeyEvent.KEY_PRESSED) { - KeyEvent ke = (KeyEvent) e; - if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_ENTER) - { + KeyEvent ke = (KeyEvent) e; + if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_ENTER) + { String selectedItem = ((List) awtComponent).getSelectedItem (); // Enter only generates an Action event if something is // selected. if (selectedItem != null) - postActionEvent (selectedItem, ke.getModifiersEx ()); - } + postActionEvent (selectedItem, ke.getModifiersEx ()); + } } super.handleEvent (e); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java index a4e280fe45f..e40a04eed92 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java @@ -40,8 +40,6 @@ package gnu.java.awt.peer.gtk; import gnu.java.awt.peer.NativeEventLoopRunningEvent; -import java.awt.AWTEvent; - /** * The Java thread representing the native GTK main loop, that is, * GtkMainThread.mainThread, terminates when GtkToolkit.gtkMain() @@ -172,9 +170,9 @@ public class GtkMainThread extends Thread { synchronized (nWindowsLock) { - if (numberOfWindows == 0) - startMainThread(); - numberOfWindows++; + if (numberOfWindows == 0) + startMainThread(); + numberOfWindows++; } } @@ -182,9 +180,9 @@ public class GtkMainThread extends Thread { synchronized (nWindowsLock) { - numberOfWindows--; - if (numberOfWindows == 0) - endMainThread(); + numberOfWindows--; + if (numberOfWindows == 0) + endMainThread(); } } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java index 898f224f5e1..c3427b18f36 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java @@ -76,15 +76,15 @@ public class GtkMenuBarPeer extends GtkMenuComponentPeer { if (hasHelpMenu) { - // Remove the (help) menu, which is after all the other items. - delMenu(((MenuBar) awtWidget).getMenuCount()); - hasHelpMenu = false; + // Remove the (help) menu, which is after all the other items. + delMenu(((MenuBar) awtWidget).getMenuCount()); + hasHelpMenu = false; } if (menu != null) { - addMenu(menu); - hasHelpMenu = true; + addMenu(menu); + hasHelpMenu = true; } } @@ -103,9 +103,9 @@ public class GtkMenuBarPeer extends GtkMenuComponentPeer // Make sure the help menu is the last one. if (hasHelpMenu) { - addHelpMenu(null); - addMenu((GtkMenuPeer) m.getPeer()); - addHelpMenu(((MenuBar) awtWidget).getHelpMenu()); + addHelpMenu(null); + addMenu((GtkMenuPeer) m.getPeer()); + addHelpMenu(((MenuBar) awtWidget).getHelpMenu()); } else addMenu((GtkMenuPeer) m.getPeer()); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java index 55b95a18d0f..1e37cefc144 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java @@ -64,9 +64,9 @@ public abstract class GtkMenuComponentPeer extends GtkGenericPeer if (f == null) { MenuContainer parent = mc.getParent (); - // Submenus inherit the font of their containing Menu(Bar). - if (parent instanceof MenuComponent) - f = parent.getFont (); + // Submenus inherit the font of their containing Menu(Bar). + if (parent instanceof MenuComponent) + f = parent.getFont (); } setFont(f); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java index 1d581c1a15c..ff6bdca9fbe 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java @@ -96,8 +96,8 @@ public class GtkMenuPeer extends GtkMenuItemPeer MenuShortcut ms = item.getShortcut (); if (ms != null) { - key = ms.getKey (); - shiftModifier = ms.usesShiftModifier (); + key = ms.getKey (); + shiftModifier = ms.usesShiftModifier (); } addItem ((MenuItemPeer) item.getPeer (), key, shiftModifier); @@ -110,8 +110,8 @@ public class GtkMenuPeer extends GtkMenuItemPeer if (ms != null) { - key = ms.getKey (); - shiftModifier = ms.usesShiftModifier (); + key = ms.getKey (); + shiftModifier = ms.usesShiftModifier (); } addItem (item, key, shiftModifier); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java index 02bf84d4e8e..7aea50991df 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java @@ -53,9 +53,9 @@ public class GtkMouseInfoPeer implements MouseInfoPeer public int fillPointWithCoords(Point p) { int[] coords = gde.getMouseCoordinates(); - p.x = coords[1]; - p.y = coords[2]; - return coords[0]; + p.x = coords[1]; + p.y = coords[2]; + return coords[0]; } public boolean isWindowUnderMouse(Window w) diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java index 69f8b494625..657a2760876 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java @@ -74,10 +74,8 @@ public class GtkScrollPanePeer extends GtkContainerPeer // If the child is in this range, GTK adds both scrollbars, but // the AWT doesn't. So set the peer's scroll policy to // GTK_POLICY_NEVER. - if ((width > dim[0] - getVScrollbarWidth () - && width <= dim[0]) - && (height > dim[1] - getHScrollbarHeight () - && height <= dim[1])) + if ((width > dim[0] - getVScrollbarWidth () && width <= dim[0]) + && (height > dim[1] - getHScrollbarHeight () && height <= dim[1])) setPolicy (ScrollPane.SCROLLBARS_NEVER); else setPolicy (((ScrollPane) awtComponent).getScrollbarDisplayPolicy ()); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java index e4147d36c97..c29706f408f 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java @@ -50,14 +50,14 @@ public class GtkScrollbarPeer extends GtkComponentPeer Scrollbar sb = (Scrollbar) awtComponent; create (sb.getOrientation (), sb.getValue (), - sb.getMinimum (), sb.getMaximum (), - sb.getUnitIncrement (), sb.getBlockIncrement (), - sb.getVisibleAmount ()); + sb.getMinimum (), sb.getMaximum (), + sb.getUnitIncrement (), sb.getBlockIncrement (), + sb.getVisibleAmount ()); } native void create (int orientation, int value, - int min, int max, int stepIncr, int pageIncr, - int visibleAmount); + int min, int max, int stepIncr, int pageIncr, + int visibleAmount); native void connectSignals (); @@ -86,7 +86,7 @@ public class GtkScrollbarPeer extends GtkComponentPeer { Scrollbar bar = (Scrollbar) awtComponent; q().postEvent(new AdjustmentEvent(bar, - AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, - type, value, true)); + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + type, value, true)); } } diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java index 6a92f86e8b0..967a2edb432 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java @@ -130,7 +130,7 @@ public class GtkSelection implements Transferable * Set as response to a requestURIs() call. Only valid when * urisDelivered is true */ - private List uris; + private List<File> uris; /** * Indicates a requestBytes(String) call was made and the @@ -163,51 +163,51 @@ public class GtkSelection implements Transferable DataFlavor[] result; synchronized (requestLock) { - // Did we request already and cache the result? - if (mimeTypesDelivered) - result = (DataFlavor[]) dataFlavors.clone(); - else - { - // Wait till there are no pending requests. - while (requestInProgress) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - - // If nobody else beat us and cached the result we try - // ourselves to get it. - if (! mimeTypesDelivered) - { - requestInProgress = true; - requestMimeTypes(clipboard); - while (! mimeTypesDelivered) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - requestInProgress = false; - } - result = dataFlavors; - if (! GtkClipboard.canCache) - { - dataFlavors = null; - mimeTypesDelivered = false; - } - requestLock.notifyAll(); - } + // Did we request already and cache the result? + if (mimeTypesDelivered) + result = (DataFlavor[]) dataFlavors.clone(); + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us and cached the result we try + // ourselves to get it. + if (! mimeTypesDelivered) + { + requestInProgress = true; + requestMimeTypes(clipboard); + while (! mimeTypesDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = dataFlavors; + if (! GtkClipboard.canCache) + { + dataFlavors = null; + mimeTypesDelivered = false; + } + requestLock.notifyAll(); + } } return result; } @@ -220,53 +220,55 @@ public class GtkSelection implements Transferable { synchronized (requestLock) { - if (mimeTypes == null) - dataFlavors = new DataFlavor[0]; - else - { - // Most likely the mimeTypes include text in which case we add an - // extra element. - ArrayList flavorsList = new ArrayList(mimeTypes.length + 1); - for (int i = 0; i < mimeTypes.length; i++) - { - try - { - if (mimeTypes[i] == GtkClipboard.stringMimeType) - { - // XXX - Fix DataFlavor.getTextPlainUnicodeFlavor() - // and also add it to the list. - flavorsList.add(DataFlavor.stringFlavor); - flavorsList.add(DataFlavor.plainTextFlavor); - } - else if (mimeTypes[i] == GtkClipboard.imageMimeType) - flavorsList.add(DataFlavor.imageFlavor); - else if (mimeTypes[i] == GtkClipboard.filesMimeType) - flavorsList.add(DataFlavor.javaFileListFlavor); - else - { - // We check the target to prevent duplicates - // of the "magic" targets above. - DataFlavor target = new DataFlavor(mimeTypes[i]); - if (! flavorsList.contains(target)) - flavorsList.add(target); - } - } - catch (ClassNotFoundException cnfe) - { - cnfe.printStackTrace(); - } - catch (NullPointerException npe) - { - npe.printStackTrace(); - } - } + if (mimeTypes == null) + dataFlavors = new DataFlavor[0]; + else + { + // Most likely the mimeTypes include text in which case we add an + // extra element. + ArrayList<DataFlavor> flavorsList = + new ArrayList<DataFlavor>(mimeTypes.length + 1); + + for (int i = 0; i < mimeTypes.length; i++) + { + try + { + if (mimeTypes[i] == GtkClipboard.stringMimeType) + { + // XXX - Fix DataFlavor.getTextPlainUnicodeFlavor() + // and also add it to the list. + flavorsList.add(DataFlavor.stringFlavor); + flavorsList.add(DataFlavor.plainTextFlavor); + } + else if (mimeTypes[i] == GtkClipboard.imageMimeType) + flavorsList.add(DataFlavor.imageFlavor); + else if (mimeTypes[i] == GtkClipboard.filesMimeType) + flavorsList.add(DataFlavor.javaFileListFlavor); + else + { + // We check the target to prevent duplicates + // of the "magic" targets above. + DataFlavor target = new DataFlavor(mimeTypes[i]); + if (! flavorsList.contains(target)) + flavorsList.add(target); + } + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } + catch (NullPointerException npe) + { + npe.printStackTrace(); + } + } - dataFlavors = new DataFlavor[flavorsList.size()]; - flavorsList.toArray(dataFlavors); - } + dataFlavors = new DataFlavor[flavorsList.size()]; + flavorsList.toArray(dataFlavors); + } - mimeTypesDelivered = true; - requestLock.notifyAll(); + mimeTypesDelivered = true; + requestLock.notifyAll(); } } @@ -279,7 +281,7 @@ public class GtkSelection implements Transferable DataFlavor[] dfs = getTransferDataFlavors(); for (int i = 0; i < dfs.length; i++) if (flavor.equals(dfs[i])) - return true; + return true; return false; } @@ -294,51 +296,51 @@ public class GtkSelection implements Transferable String result; synchronized (requestLock) { - // Did we request already and cache the result? - if (textDelivered) - result = text; - else - { - // Wait till there are no pending requests. - while (requestInProgress) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - - // If nobody else beat us we try ourselves to get and - // caching the result. - if (! textDelivered) - { - requestInProgress = true; - requestText(clipboard); - while (! textDelivered) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - requestInProgress = false; - } - result = text; - if (! GtkClipboard.canCache) - { - text = null; - textDelivered = false; - } - requestLock.notifyAll(); - } + // Did we request already and cache the result? + if (textDelivered) + result = text; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! textDelivered) + { + requestInProgress = true; + requestText(clipboard); + while (! textDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = text; + if (! GtkClipboard.canCache) + { + text = null; + textDelivered = false; + } + requestLock.notifyAll(); + } } return result; } @@ -351,9 +353,9 @@ public class GtkSelection implements Transferable { synchronized (requestLock) { - this.text = text; - textDelivered = true; - requestLock.notifyAll(); + this.text = text; + textDelivered = true; + requestLock.notifyAll(); } } @@ -367,54 +369,56 @@ public class GtkSelection implements Transferable Image result; synchronized (requestLock) { - // Did we request already and cache the result? - if (imageDelivered) - result = image; - else - { - // Wait till there are no pending requests. - while (requestInProgress) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - - // If nobody else beat us we try ourselves to get and - // caching the result. - if (! imageDelivered) - { - requestInProgress = true; - requestImage(clipboard); - while (! imageDelivered) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - requestInProgress = false; - } - if (imagePointer != null) - image = new GtkImage(imagePointer); - imagePointer = null; - result = image; - if (! GtkClipboard.canCache) - { - image = null; - imageDelivered = false; - } - requestLock.notifyAll(); - } + // Did we request already and cache the result? + if (imageDelivered) + result = image; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! imageDelivered) + { + requestInProgress = true; + requestImage(clipboard); + while (! imageDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + + if (imagePointer != null) + image = new GtkImage(imagePointer); + + imagePointer = null; + result = image; + if (! GtkClipboard.canCache) + { + image = null; + imageDelivered = false; + } + requestLock.notifyAll(); + } } return result; } @@ -430,9 +434,9 @@ public class GtkSelection implements Transferable { synchronized (requestLock) { - this.imagePointer = pointer; - imageDelivered = true; - requestLock.notifyAll(); + this.imagePointer = pointer; + imageDelivered = true; + requestLock.notifyAll(); } } @@ -441,56 +445,56 @@ public class GtkSelection implements Transferable * URIs/Files and if not requests them and waits till they are * available. */ - private List getURIs() + private List<File> getURIs() { - List result; + List<File> result; synchronized (requestLock) { - // Did we request already and cache the result? - if (urisDelivered) - result = uris; - else - { - // Wait till there are no pending requests. - while (requestInProgress) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - - // If nobody else beat us we try ourselves to get and - // caching the result. - if (! urisDelivered) - { - requestInProgress = true; - requestURIs(clipboard); - while (! urisDelivered) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - requestInProgress = false; - } - result = uris; - if (! GtkClipboard.canCache) - { - uris = null; - urisDelivered = false; - } - requestLock.notifyAll(); - } + // Did we request already and cache the result? + if (urisDelivered) + result = uris; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! urisDelivered) + { + requestInProgress = true; + requestURIs(clipboard); + while (! urisDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = uris; + if (! GtkClipboard.canCache) + { + uris = null; + urisDelivered = false; + } + requestLock.notifyAll(); + } } return result; } @@ -503,26 +507,26 @@ public class GtkSelection implements Transferable { synchronized (requestLock) { - if (uris != null && uris.length != 0) - { - ArrayList list = new ArrayList(uris.length); - for (int i = 0; i < uris.length; i++) - { - try - { - URI uri = new URI(uris[i]); - if (uri.getScheme().equals("file")) - list.add(new File(uri)); - } - catch (URISyntaxException use) - { - } - } - this.uris = list; - } - - urisDelivered = true; - requestLock.notifyAll(); + if (uris != null && uris.length != 0) + { + ArrayList<File> list = new ArrayList<File>(uris.length); + for (int i = 0; i < uris.length; i++) + { + try + { + URI uri = new URI(uris[i]); + if (uri.getScheme().equals("file")) + list.add(new File(uri)); + } + catch (URISyntaxException use) + { + } + } + this.uris = list; + } + + urisDelivered = true; + requestLock.notifyAll(); } } @@ -537,39 +541,39 @@ public class GtkSelection implements Transferable byte[] result; synchronized (requestLock) { - // Wait till there are no pending requests. - while (requestInProgress) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - - // Request bytes and wait till they are available. - requestInProgress = true; - requestBytes(clipboard, target); - while (! bytesDelivered) - { - try - { - requestLock.wait(); - } - catch (InterruptedException ie) - { - // ignored - } - } - result = bytes; - bytes = null; - bytesDelivered = false; - requestInProgress = false; + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // Request bytes and wait till they are available. + requestInProgress = true; + requestBytes(clipboard, target); + while (! bytesDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + result = bytes; + bytes = null; + bytesDelivered = false; + requestInProgress = false; - requestLock.notifyAll(); + requestLock.notifyAll(); } return result; } @@ -583,9 +587,9 @@ public class GtkSelection implements Transferable { synchronized (requestLock) { - this.bytes = bytes; - bytesDelivered = true; - requestLock.notifyAll(); + this.bytes = bytes; + bytesDelivered = true; + requestLock.notifyAll(); } } @@ -596,30 +600,30 @@ public class GtkSelection implements Transferable // try one more time through getBytes(). if (flavor.equals(DataFlavor.stringFlavor)) { - String text = getText(); - if (text != null) - return text; + String text = getText(); + if (text != null) + return text; } if (flavor.equals(DataFlavor.plainTextFlavor)) { - String text = getText(); - if (text != null) - return new StringBufferInputStream(text); + String text = getText(); + if (text != null) + return new StringBufferInputStream(text); } if (flavor.equals(DataFlavor.imageFlavor)) { - Image image = getImage(); - if (image != null) - return image; + Image image = getImage(); + if (image != null) + return image; } if (flavor.equals(DataFlavor.javaFileListFlavor)) { - List uris = getURIs(); - if (uris != null) - return uris; + List<File> uris = getURIs(); + if (uris != null) + return uris; } byte[] bytes = getBytes(flavor.getMimeType()); @@ -628,20 +632,20 @@ public class GtkSelection implements Transferable if (flavor.isMimeTypeSerializedObject()) { - try - { - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bais); - return ois.readObject(); - } - catch (IOException ioe) - { - ioe.printStackTrace(); - } - catch (ClassNotFoundException cnfe) - { - cnfe.printStackTrace(); - } + try + { + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(bais); + return ois.readObject(); + } + catch (IOException ioe) + { + ioe.printStackTrace(); + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } } if (flavor.isRepresentationClassInputStream()) diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java index 5d9be1aec63..0c7d3a860e8 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java @@ -100,8 +100,8 @@ public class GtkTextAreaPeer extends GtkComponentPeer // GtkComponent.create. if (f == null) { - f = new Font ("Dialog", Font.PLAIN, 12); - awtComponent.setFont (f); + f = new Font ("Dialog", Font.PLAIN, 12); + awtComponent.setFont (f); } FontMetrics fm = getFontMetrics (f); @@ -154,11 +154,11 @@ public class GtkTextAreaPeer extends GtkComponentPeer int width = 0; if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH - || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) height = getHScrollbarHeight (); if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH - || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) width = getVScrollbarWidth (); Font f = awtComponent.getFont (); @@ -183,11 +183,11 @@ public class GtkTextAreaPeer extends GtkComponentPeer int width = 0; if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH - || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) height = getHScrollbarHeight (); if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH - || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) width = getVScrollbarWidth (); Font f = awtComponent.getFont (); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java index 763304864e0..9e62c8e7975 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java @@ -94,8 +94,8 @@ public class GtkTextFieldPeer extends GtkComponentPeer // GtkComponent.create. if (f == null) { - f = new Font ("Dialog", Font.PLAIN, 12); - awtComponent.setFont (f); + f = new Font ("Dialog", Font.PLAIN, 12); + awtComponent.setFont (f); } FontMetrics fm = getFontMetrics (f); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java index f746a47479f..df18d39c9d2 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -1,5 +1,5 @@ /* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers - Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006 + Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,6 +39,7 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import gnu.java.awt.AWTUtilities; import gnu.java.awt.EmbeddedWindow; import gnu.java.awt.dnd.GtkMouseDragGestureRecognizer; import gnu.java.awt.dnd.peer.gtk.GtkDragSourceContextPeer; @@ -86,6 +87,7 @@ import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import java.awt.dnd.InvalidDnDOperationException; import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.font.TextAttribute; import java.awt.im.InputMethodHighlight; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; @@ -104,8 +106,8 @@ import java.awt.peer.LabelPeer; import java.awt.peer.ListPeer; import java.awt.peer.MenuBarPeer; import java.awt.peer.MenuItemPeer; -import java.awt.peer.MouseInfoPeer; import java.awt.peer.MenuPeer; +import java.awt.peer.MouseInfoPeer; import java.awt.peer.PanelPeer; import java.awt.peer.PopupMenuPeer; import java.awt.peer.RobotPeer; @@ -132,9 +134,11 @@ import javax.imageio.spi.IIORegistry; public class GtkToolkit extends gnu.java.awt.ClasspathToolkit { + static final Object GTK_LOCK; + private static EventQueue q; - static native void gtkInit(int portableNativeSync); + static native void gtkInit(int portableNativeSync, Object lock); static native void gtkMain(); @@ -154,8 +158,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit portableNativeSync = 1; // true else portableNativeSync = 0; // false - - gtkInit(portableNativeSync); + + GTK_LOCK = new String("GTK LOCK"); + gtkInit(portableNativeSync, GTK_LOCK); } public GtkToolkit () @@ -167,14 +172,14 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit private native void getScreenSizeDimensions(int[] xy); public int checkImage (Image image, int width, int height, - ImageObserver observer) + ImageObserver observer) { int status = ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; if (image instanceof GtkImage) - return ((GtkImage) image).checkImage (observer); + return ((GtkImage) image).checkImage (observer); if (image instanceof AsyncImage) return ((AsyncImage) image).checkImage(observer); @@ -208,11 +213,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit Image image; try { - image = CairoSurface.getBufferedImage( new GtkImage( filename ) ); + image = CairoSurface.getBufferedImage( new GtkImage( filename ) ); } catch (IllegalArgumentException iae) { - image = null; + image = null; } return imageOrError(image); } @@ -230,11 +235,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit Image image; try { - image = CairoSurface.getBufferedImage( new GtkImage( producer ) ); + image = CairoSurface.getBufferedImage( new GtkImage( producer ) ); } catch (IllegalArgumentException iae) { - image = null; + image = null; } return imageOrError(image); } @@ -245,13 +250,13 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit Image image; try { - byte[] data = new byte[ imagelength ]; - System.arraycopy(imagedata, imageoffset, data, 0, imagelength); - image = CairoSurface.getBufferedImage( new GtkImage( data ) ); + byte[] data = new byte[ imagelength ]; + System.arraycopy(imagedata, imageoffset, data, 0, imagelength); + image = CairoSurface.getBufferedImage( new GtkImage( data ) ); } catch (IllegalArgumentException iae) { - image = null; + image = null; } return imageOrError(image); } @@ -275,22 +280,22 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit { /* Return the GDK-native ABGR format */ return new DirectColorModel(32, - 0x000000FF, - 0x0000FF00, - 0x00FF0000, - 0xFF000000); + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); } public String[] getFontList () { return (new String[] { "Dialog", - "DialogInput", - "Monospaced", - "Serif", - "SansSerif" }); + "DialogInput", + "Monospaced", + "Serif", + "SansSerif" }); } - static class LRUCache extends LinkedHashMap + static class LRUCache<K,V> extends LinkedHashMap<K,V> { int max_entries; public LRUCache(int max) @@ -304,8 +309,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit } } - private LRUCache fontCache = new LRUCache(50); - private LRUCache imageCache = new LRUCache(50); + private LRUCache<Map,ClasspathFontPeer> fontCache = + new LRUCache<Map,ClasspathFontPeer>(50); + private LRUCache<Object,Image> imageCache = new LRUCache<Object,Image>(50); public FontMetrics getFontMetrics (Font font) { @@ -315,7 +321,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public Image getImage (String filename) { if (imageCache.containsKey(filename)) - return (Image) imageCache.get(filename); + return imageCache.get(filename); else { Image im = createImage(filename); @@ -327,7 +333,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit public Image getImage (URL url) { if (imageCache.containsKey(url)) - return (Image) imageCache.get(url); + return imageCache.get(url); else { Image im = createImage(url); @@ -378,12 +384,12 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit * assumes the image is already prepared for rendering. */ public boolean prepareImage (Image image, int width, int height, - ImageObserver observer) + ImageObserver observer) { /* GtkImages are always prepared, as long as they're loaded. */ if (image instanceof GtkImage) - return ((((GtkImage)image).checkImage (observer) & - ImageObserver.ALLBITS) != 0); + return ((((GtkImage)image).checkImage (observer) + & ImageObserver.ALLBITS) != 0); if (image instanceof AsyncImage) { @@ -411,11 +417,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit /* Make the Peer reflect the state of the Component */ if (! (c instanceof Window)) { - cp.setCursor (c.getCursor ()); + cp.setCursor (c.getCursor ()); - Rectangle bounds = c.getBounds (); - cp.setBounds (bounds.x, bounds.y, bounds.width, bounds.height); - cp.setVisible (c.isVisible ()); + Rectangle bounds = c.getBounds (); + cp.setBounds (bounds.x, bounds.y, bounds.width, bounds.height); + cp.setVisible (c.isVisible ()); } } @@ -563,7 +569,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit */ private FontPeer getFontPeer (String name, int style, int size) { - Map attrs = new HashMap (); + Map<TextAttribute,Object> attrs = new HashMap<TextAttribute,Object>(); ClasspathFontPeer.copyStyleToAttrs (style, attrs); ClasspathFontPeer.copySizeToAttrs (size, attrs); return getClasspathFontPeer (name, attrs); @@ -575,16 +581,17 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit * model, hence "ClasspathFontPeer". */ - public ClasspathFontPeer getClasspathFontPeer (String name, Map attrs) + public ClasspathFontPeer getClasspathFontPeer (String name, + Map<?,?> attrs) { - Map keyMap = new HashMap (attrs); + Map<Object,Object> keyMap = new HashMap<Object,Object>(attrs); // We don't know what kind of "name" the user requested (logical, face, // family), and we don't actually *need* to know here. The worst case // involves failure to consolidate fonts with the same backend in our // cache. This is harmless. keyMap.put ("GtkToolkit.RequestedFontName", name); if (fontCache.containsKey (keyMap)) - return (ClasspathFontPeer) fontCache.get (keyMap); + return fontCache.get (keyMap); else { ClasspathFontPeer newPeer = new GdkFontPeer (name, attrs); @@ -619,11 +626,10 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit return new GtkDragSourceContextPeer(e); } - public DragGestureRecognizer createDragGestureRecognizer(Class recognizer, - DragSource ds, - Component comp, - int actions, - DragGestureListener l) + public <T extends DragGestureRecognizer> T + createDragGestureRecognizer(Class<T> recognizer, DragSource ds, + Component comp, int actions, + DragGestureListener l) { if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer") && ! GraphicsEnvironment.isHeadless()) @@ -631,7 +637,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit GtkMouseDragGestureRecognizer gestureRecognizer = new GtkMouseDragGestureRecognizer(ds, comp, actions, l); gestureRecognizer.registerListeners(); - return gestureRecognizer; + return recognizer.cast(gestureRecognizer); } else { @@ -639,7 +645,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit } } - public Map mapInputMethodHighlight(InputMethodHighlight highlight) + public Map<TextAttribute,?> mapInputMethodHighlight(InputMethodHighlight highlight) { throw new Error("not implemented"); } @@ -668,6 +674,22 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit return new GdkRobotPeer (screen); } + public boolean getLockingKeyState(int keyCode) + { + int state = getLockState(keyCode); + + if (state != -1) + return state == 1; + + if (AWTUtilities.isValidKey(keyCode)) + throw new UnsupportedOperationException + ("cannot get locking state of key code " + keyCode); + + throw new IllegalArgumentException("invalid key code " + keyCode); + } + + protected native int getLockState(int keyCode); + public void registerImageIOSpis(IIORegistry reg) { GdkPixbufDecoder.registerSpis(reg); diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java index 8d49719b1d3..1451dd93354 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java @@ -172,19 +172,17 @@ public class GtkWindowPeer extends GtkContainerPeer public void setBounds (int x, int y, int width, int height) { - if (x != getX() - || y != getY() - || width != getWidth() - || height != getHeight()) + if (x != getX() || y != getY() || width != getWidth() + || height != getHeight()) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; + 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); + nativeSetBounds (x, y, + width - insets.left - insets.right, + height - insets.top - insets.bottom); } } @@ -211,7 +209,7 @@ public class GtkWindowPeer extends GtkContainerPeer width = awtComponent.getWidth(); height = awtComponent.getHeight(); setSize (width - insets.left - insets.right, - height - insets.top - insets.bottom); + height - insets.top - insets.bottom); gtkWindowSetResizable (resizable); } @@ -253,22 +251,20 @@ public class GtkWindowPeer extends GtkContainerPeer awtComponent.dispatchEvent(ev); } - if (frame_width != getWidth() - || frame_height != getHeight()) + if (frame_width != getWidth() || frame_height != getHeight()) { - this.width = frame_width; - this.height = frame_height; - q().postEvent(new ComponentEvent(awtComponent, - ComponentEvent.COMPONENT_RESIZED)); + this.width = frame_width; + this.height = frame_height; + q().postEvent(new ComponentEvent(awtComponent, + ComponentEvent.COMPONENT_RESIZED)); } - if (frame_x != getX() - || frame_y != getY()) + if (frame_x != getX() || frame_y != getY()) { - this.x = frame_x; - this.y = frame_y; - q().postEvent(new ComponentEvent(awtComponent, - ComponentEvent.COMPONENT_MOVED)); + this.x = frame_x; + this.y = frame_y; + q().postEvent(new ComponentEvent(awtComponent, + ComponentEvent.COMPONENT_MOVED)); } } @@ -287,8 +283,8 @@ public class GtkWindowPeer extends GtkContainerPeer { if (id == WindowEvent.WINDOW_STATE_CHANGED) { - if (windowState != newState) - { + if (windowState != newState) + { // Post old styleWindowEvent with WINDOW_ICONIFIED or // WINDOW_DEICONIFIED if appropriate. if ((windowState & Frame.ICONIFIED) != 0 @@ -302,10 +298,10 @@ public class GtkWindowPeer extends GtkContainerPeer WindowEvent.WINDOW_ICONIFIED, opposite, 0, 0)); // Post new-style WindowStateEvent. - q().postEvent (new WindowEvent ((Window) awtComponent, id, + q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite, windowState, newState)); - windowState = newState; - } + windowState = newState; + } } else q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite)); @@ -384,7 +380,7 @@ public class GtkWindowPeer extends GtkContainerPeer } protected void postMouseEvent(int id, long when, int mods, int x, int y, - int clickCount, boolean popupTrigger) + 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 @@ -392,8 +388,8 @@ public class GtkWindowPeer extends GtkContainerPeer // insets but GtkFramePeer and GtkDialogPeer insets will be // non-zero. super.postMouseEvent (id, when, mods, - x + insets.left, y + insets.top, - clickCount, popupTrigger); + x + insets.left, y + insets.top, + clickCount, popupTrigger); } // We override this to keep it in sync with our internal diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java index 62dbb45d81a..88438862b34 100644 --- a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java +++ b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java @@ -207,11 +207,11 @@ public class VolatileImageGraphics extends ComponentGraphics if (img instanceof GtkVolatileImage && (comp == null || comp instanceof AlphaComposite)) { - owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, - x, y, - ((GtkVolatileImage)img).width, - ((GtkVolatileImage)img).height ); - return true; + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, + ((GtkVolatileImage)img).width, + ((GtkVolatileImage)img).height ); + return true; } return super.drawImage( img, x, y, observer ); } @@ -222,9 +222,9 @@ public class VolatileImageGraphics extends ComponentGraphics if ((img instanceof GtkVolatileImage) && (comp == null || comp instanceof AlphaComposite)) { - owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, - x, y, width, height ); - return true; + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, width, height ); + return true; } return super.drawImage( img, x, y, width, height, observer ); } @@ -254,8 +254,8 @@ public class VolatileImageGraphics extends ComponentGraphics transform.transform(points, 0, points, 0, 2); Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], - points[2] - points[0], - points[3] - points[1]); + points[2] - points[0], + points[3] - points[1]); Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); current = current.getSubimage((int)deviceBounds.getX(), diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java b/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java index 5116769389e..9b53b278b26 100644 --- a/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java @@ -1,5 +1,5 @@ /* QtToolkit.java -- - Copyright (C) 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,6 +37,7 @@ exception statement from your version. */ package gnu.java.awt.peer.qt; +import gnu.java.awt.ClasspathToolkit; import gnu.java.awt.EmbeddedWindow; import gnu.java.awt.peer.ClasspathFontPeer; import gnu.java.awt.peer.EmbeddedWindowPeer; @@ -50,56 +51,56 @@ import java.awt.Choice; import java.awt.Dialog; import java.awt.Dimension; import java.awt.EventQueue; +import java.awt.FileDialog; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Label; import java.awt.List; -import java.awt.MenuBar; import java.awt.Menu; +import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.Panel; -import java.awt.TextArea; -import java.awt.TextField; -import java.awt.FileDialog; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; import java.awt.PopupMenu; import java.awt.PrintJob; -import java.awt.Scrollbar; import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; import java.awt.Window; import java.awt.datatransfer.Clipboard; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.peer.DragSourceContextPeer; import java.awt.event.AWTEventListener; +import java.awt.im.InputMethodHighlight; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; -import java.awt.im.InputMethodHighlight; import java.awt.peer.ButtonPeer; -import java.awt.peer.FontPeer; -import java.awt.peer.PanelPeer; import java.awt.peer.CanvasPeer; -import java.awt.peer.FramePeer; -import java.awt.peer.PopupMenuPeer; import java.awt.peer.CheckboxMenuItemPeer; -import java.awt.peer.LabelPeer; -import java.awt.peer.RobotPeer; import java.awt.peer.CheckboxPeer; -import java.awt.peer.ScrollPanePeer; import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; import java.awt.peer.ListPeer; -import java.awt.peer.ScrollbarPeer; import java.awt.peer.MenuBarPeer; -import java.awt.peer.TextAreaPeer; -import java.awt.peer.DialogPeer; import java.awt.peer.MenuItemPeer; -import java.awt.peer.TextFieldPeer; -import java.awt.peer.FileDialogPeer; import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; import java.awt.peer.WindowPeer; import java.io.InputStream; import java.net.URL; @@ -107,8 +108,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; -import gnu.java.awt.ClasspathToolkit; - public class QtToolkit extends ClasspathToolkit { public static EventQueue eventQueue = null; // the native event queue @@ -163,7 +162,9 @@ public class QtToolkit extends ClasspathToolkit if( guiThread == null ) initToolkit(); - while (!guiThread.isRunning()); // make sure the GUI thread has started. + // make sure the GUI thread has started. + while (!guiThread.isRunning()) + ; if( graphicsEnv == null ) graphicsEnv = new QtGraphicsEnvironment( this ); diff --git a/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java b/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java index 9a3db012583..b86eea50b20 100644 --- a/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java +++ b/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java @@ -135,7 +135,8 @@ public class JavaPrinterGraphics extends Graphics implements PrinterGraphics { int index = 0; while(spoolPage(out, printable, pageFormat, index++) == - Printable.PAGE_EXISTS); + Printable.PAGE_EXISTS) + ; } out.println("%%Trailer"); out.println("%%EOF"); diff --git a/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java b/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java index e4cc8199a54..4e052a1d3f4 100644 --- a/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java +++ b/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java @@ -191,7 +191,8 @@ class PostScriptGraphics2D extends Graphics2D { int index = 0; while(spoolPage(out, printable, pageFormat, index++) == - Printable.PAGE_EXISTS); + Printable.PAGE_EXISTS) + ; } out.println("%%Trailer"); out.println("%%EOF"); diff --git a/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java b/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java index edf07d760d3..b78a8141384 100644 --- a/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java +++ b/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java @@ -153,7 +153,7 @@ public class ScanEngine writer = new StAXWriter(os); root = new Root(); - final ScannerState start = current = new GenericScannerState(root);; + final ScannerState start = current = new GenericScannerState(root); ScannerState conf; // Use the ReportingScannerState to debug serialization issues. diff --git a/libjava/classpath/gnu/java/io/Base64InputStream.java b/libjava/classpath/gnu/java/io/Base64InputStream.java index b0824ab6935..1f5d220dbb6 100644 --- a/libjava/classpath/gnu/java/io/Base64InputStream.java +++ b/libjava/classpath/gnu/java/io/Base64InputStream.java @@ -139,7 +139,9 @@ public class Base64InputStream extends FilterInputStream while (count < len) { int i; - while (Character.isWhitespace((char) (i = in.read()))); + while (Character.isWhitespace((char) (i = in.read()))) + ; + int pos = BASE_64.indexOf((char) i); if (pos >= 0) { @@ -173,11 +175,13 @@ public class Base64InputStream extends FilterInputStream case 1: throw new IOException("malformed Base-64 input"); case 2: - while (Character.isWhitespace((char) (i = in.read()))); + while (Character.isWhitespace((char) (i = in.read()))) + ; if (i != BASE_64_PAD) throw new IOException("malformed Base-64 input"); case 3: - while (Character.isWhitespace((char) (i = in.read()))); + while (Character.isWhitespace((char) (i = in.read()))) + ; } eof = true; break; diff --git a/libjava/classpath/gnu/java/io/class-dependencies.conf b/libjava/classpath/gnu/java/io/class-dependencies.conf deleted file mode 100644 index 2500f6b14b5..00000000000 --- a/libjava/classpath/gnu/java/io/class-dependencies.conf +++ /dev/null @@ -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 diff --git a/libjava/classpath/gnu/java/lang/management/BeanImpl.java b/libjava/classpath/gnu/java/lang/management/BeanImpl.java index e5b47181273..59e79a550d3 100644 --- a/libjava/classpath/gnu/java/lang/management/BeanImpl.java +++ b/libjava/classpath/gnu/java/lang/management/BeanImpl.java @@ -37,6 +37,8 @@ exception statement from your version. */ package gnu.java.lang.management; +import gnu.javax.management.Translator; + import java.lang.management.ManagementPermission; import java.lang.reflect.Array; @@ -124,7 +126,7 @@ public class BeanImpl new OpenMBeanAttributeInfoSupport[oldA.length]; for (int a = 0; a < oldA.length; ++a) { - OpenMBeanParameterInfo param = translate(oldA[a].getType()); + OpenMBeanParameterInfo param = Translator.translate(oldA[a].getType()); if (param.getMinValue() == null) { Object[] lv; @@ -134,7 +136,8 @@ public class BeanImpl lv = param.getLegalValues().toArray(); attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), oldA[a].getDescription(), - param.getOpenType(), + ((OpenType<Object>) + param.getOpenType()), oldA[a].isReadable(), oldA[a].isWritable(), oldA[a].isIs(), @@ -144,13 +147,16 @@ public class BeanImpl else attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), oldA[a].getDescription(), - param.getOpenType(), + ((OpenType<Object>) + param.getOpenType()), oldA[a].isReadable(), oldA[a].isWritable(), oldA[a].isIs(), param.getDefaultValue(), - param.getMinValue(), - param.getMaxValue()); + ((Comparable<Object>) + param.getMinValue()), + ((Comparable<Object>) + param.getMaxValue())); } MBeanConstructorInfo[] oldC = info.getConstructors(); OpenMBeanConstructorInfo[] cons = new OpenMBeanConstructorInfoSupport[oldC.length]; @@ -166,7 +172,7 @@ public class BeanImpl new OpenMBeanOperationInfoSupport(oldO[a].getName(), oldO[a].getDescription(), translateSignature(oldO[a].getSignature()), - translate(oldO[a].getReturnType()).getOpenType(), + Translator.translate(oldO[a].getReturnType()).getOpenType(), oldO[a].getImpact()); openInfo = new OpenMBeanInfoSupport(info.getClassName(), info.getDescription(), attribs, cons, ops, info.getNotifications()); @@ -201,32 +207,36 @@ public class BeanImpl return ((Enum) value).name(); Class vClass = value.getClass(); if (vClass.isArray()) - return value; + vClass = vClass.getComponentType(); String cName = vClass.getName(); String[] allowedTypes = OpenType.ALLOWED_CLASSNAMES; for (int a = 0; a < allowedTypes.length; ++a) if (cName.equals(allowedTypes[a])) return value; - if (value instanceof List) - { - List l = (List) value; - Class e = null; - TypeVariable[] vars = vClass.getTypeParameters(); - for (int a = 0; a < vars.length; ++a) - if (vars[a].getName().equals("E")) - e = (Class) vars[a].getGenericDeclaration(); - if (e == null) - e = Object.class; - Object[] array = (Object[]) Array.newInstance(e, l.size()); - return l.toArray(array); - } OpenMBeanInfo info = (OpenMBeanInfo) getMBeanInfo(); - OpenMBeanAttributeInfo[] attribs = - (OpenMBeanAttributeInfo[]) info.getAttributes(); + MBeanAttributeInfo[] attribs = + (MBeanAttributeInfo[]) info.getAttributes(); OpenType type = null; for (int a = 0; a < attribs.length; ++a) - if (attribs[a].getName().equals("attribute")) - type = attribs[a].getOpenType(); + if (attribs[a].getName().equals(attribute)) + type = ((OpenMBeanAttributeInfo) attribs[a]).getOpenType(); + if (value instanceof List) + { + try + { + Class e = + Class.forName(((ArrayType) type).getElementOpenType().getClassName()); + List l = (List) value; + Object[] array = (Object[]) Array.newInstance(e, l.size()); + return l.toArray(array); + } + catch (ClassNotFoundException e) + { + throw (InternalError) (new InternalError("The class of the list " + + "element type could not " + + "be created").initCause(e)); + } + } if (value instanceof Map) { TabularType ttype = (TabularType) type; @@ -319,19 +329,13 @@ public class BeanImpl return getCachedMBeanInfo(); } - private OpenType getTypeFromClass(Class c) - throws OpenDataException - { - return translate(c.getName()).getOpenType(); - } - private OpenMBeanParameterInfo[] translateSignature(MBeanParameterInfo[] oldS) throws OpenDataException { OpenMBeanParameterInfo[] sig = new OpenMBeanParameterInfoSupport[oldS.length]; for (int a = 0; a < oldS.length; ++a) { - OpenMBeanParameterInfo param = translate(oldS[a].getType()); + OpenMBeanParameterInfo param = Translator.translate(oldS[a].getType()); if (param.getMinValue() == null) { Object[] lv; @@ -341,179 +345,24 @@ public class BeanImpl lv = param.getLegalValues().toArray(); sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), oldS[a].getDescription(), - param.getOpenType(), + ((OpenType<Object>) + param.getOpenType()), param.getDefaultValue(), lv); } else sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), oldS[a].getDescription(), - param.getOpenType(), + ((OpenType<Object>) + param.getOpenType()), param.getDefaultValue(), - param.getMinValue(), - param.getMaxValue()); + ((Comparable<Object>) + param.getMinValue()), + ((Comparable<Object>) + param.getMaxValue())); } return sig; } - private OpenMBeanParameterInfo translate(String type) - throws OpenDataException - { - if (type.equals("boolean") || type.equals(Boolean.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.BOOLEAN, - null, - new Object[] { - Boolean.TRUE, - Boolean.FALSE - }); - if (type.equals("byte") || type.equals(Byte.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.BYTE, - null, - Byte.valueOf(Byte.MIN_VALUE), - Byte.valueOf(Byte.MAX_VALUE)); - if (type.equals("char") || type.equals(Character.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.CHARACTER, - null, - Character.valueOf(Character.MIN_VALUE), - Character.valueOf(Character.MAX_VALUE)); - if (type.equals("double") || type.equals(Double.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.DOUBLE, - null, - Double.valueOf(Double.MIN_VALUE), - Double.valueOf(Double.MAX_VALUE)); - if (type.equals("float") || type.equals(Float.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.FLOAT, - null, - Float.valueOf(Float.MIN_VALUE), - Float.valueOf(Float.MAX_VALUE)); - if (type.equals("int") || type.equals(Integer.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.INTEGER, - null, - Integer.valueOf(Integer.MIN_VALUE), - Integer.valueOf(Integer.MAX_VALUE)); - if (type.equals("long") || type.equals(Long.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.LONG, - null, - Long.valueOf(Long.MIN_VALUE), - Long.valueOf(Long.MAX_VALUE)); - if (type.equals("short") || type.equals(Short.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.SHORT, - null, - Short.valueOf(Short.MIN_VALUE), - Short.valueOf(Short.MAX_VALUE)); - if (type.equals(String.class.getName())) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.STRING); - if (type.equals("void")) - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.VOID); - if (type.startsWith("java.util.Map")) - { - int lparam = type.indexOf("<"); - int comma = type.indexOf(",", lparam); - int rparam = type.indexOf(">", comma); - String key = type.substring(lparam + 1, comma).trim(); - OpenType k = translate(key).getOpenType(); - OpenType v = translate(type.substring(comma + 1, rparam).trim()).getOpenType(); - CompositeType ctype = new CompositeType(Map.class.getName(), Map.class.getName(), - new String[] { "key", "value" }, - new String[] { "Map key", "Map value"}, - new OpenType[] { k, v}); - TabularType ttype = new TabularType(key, key, ctype, - new String[] { "key" }); - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - ttype); - } - if (type.startsWith("java.util.List")) - { - int lparam = type.indexOf("<"); - int rparam = type.indexOf(">"); - OpenType e = translate(type.substring(lparam + 1, rparam).trim()).getOpenType(); - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - new ArrayType(1, e) - ); - } - Class c; - try - { - c = Class.forName(type); - } - catch (ClassNotFoundException e) - { - throw (InternalError) - (new InternalError("The class for a type used in a management bean " + - "could not be loaded.").initCause(e)); - } - if (c.isEnum()) - { - Object[] values = c.getEnumConstants(); - String[] names = new String[values.length]; - for (int a = 0; a < values.length; ++a) - names[a] = values[a].toString(); - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - SimpleType.STRING, - null, - (Object[]) names); - } - try - { - c.getMethod("from", new Class[] { CompositeData.class }); - Method[] methods = c.getMethods(); - List names = new ArrayList(); - List types = new ArrayList(); - for (int a = 0; a < methods.length; ++a) - { - String name = methods[a].getName(); - if (name.startsWith("get")) - { - names.add(name.substring(3)); - types.add(getTypeFromClass(methods[a].getReturnType())); - } - } - String[] fields = (String[]) names.toArray(); - CompositeType ctype = new CompositeType(c.getName(), c.getName(), - fields, fields, - (OpenType[]) types.toArray()); - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - ctype); - } - catch (NoSuchMethodException e) - { - /* Ignored; we expect this if this isn't a from(CompositeData) class */ - } - if (c.isArray()) - { - int depth; - for (depth = 0; c.getName().charAt(depth) == '['; ++depth); - OpenType ot = getTypeFromClass(c.getComponentType()); - return new OpenMBeanParameterInfoSupport("TransParam", - "Translated parameter", - new ArrayType(depth, ot) - ); - } - throw new InternalError("The type used does not have an open type translation."); - } } diff --git a/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java index 9eefc0d9db5..07fb7bf0355 100644 --- a/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java +++ b/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java @@ -82,6 +82,11 @@ public final class OperatingSystemMXBeanImpl return System.getProperty("os.name"); } + public double getSystemLoadAverage() + { + return VMOperatingSystemMXBeanImpl.getSystemLoadAverage(); + } + public String getVersion() { return System.getProperty("os.version"); diff --git a/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java index 609b58da737..5d0282301e3 100644 --- a/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java +++ b/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java @@ -83,7 +83,19 @@ public final class ThreadMXBeanImpl */ private static final String TIME_ENABLED = "gnu.java.lang.management.ThreadTimeInitallyEnabled"; - + + /** + * Constant for monitor usage monitoring support. + */ + private static final String MONITOR_SUPPORT = + "gnu.java.lang.management.MonitorUsageMonitoringSupport"; + + /** + * Constant for ownable synchronizer usage monitoring support. + */ + private static final String SYNCHRONIZER_SUPPORT = + "gnu.java.lang.management.OwnableSynchronizerUsageMonitoringSupport"; + /** * Flag to indicate whether time monitoring is enabled or not. */ @@ -112,6 +124,23 @@ public final class ThreadMXBeanImpl contentionEnabled = false; } + public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, + boolean lockedSynchronizers) + { + return getThreadInfo(getAllThreadIds(), lockedMonitors, + lockedSynchronizers); + } + + public long[] findDeadlockedThreads() + { + checkMonitorPermissions(); + if (!isSynchronizerUsageSupported()) + throw new UnsupportedOperationException("Ownable synchronizer usage " + + "monitoring is not provided " + + "by this VM."); + return VMThreadMXBeanImpl.findDeadlockedThreads(); + } + public long[] findMonitorDeadlockedThreads() { checkMonitorPermissions(); @@ -207,6 +236,27 @@ public final class ThreadMXBeanImpl return infos; } + public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, + boolean lockedSynchronizers) + { + checkMonitorPermissions(); + if (lockedMonitors && !isObjectMonitorUsageSupported()) + throw new UnsupportedOperationException("Monitor usage monitoring is " + + "not provided by this VM."); + if (lockedSynchronizers && !isSynchronizerUsageSupported()) + throw new UnsupportedOperationException("Ownable synchronizer usage " + + "monitoring is not provided " + + "by this VM."); + ThreadInfo[] infos = getThreadInfo(ids, Integer.MAX_VALUE); + if (lockedMonitors) + for (ThreadInfo info : infos) + VMThreadMXBeanImpl.getMonitorInfo(info); + if (lockedSynchronizers) + for (ThreadInfo info : infos) + VMThreadMXBeanImpl.getLockInfo(info); + return infos; + } + public long getThreadUserTime(long id) { if (!isThreadCpuTimeSupported()) @@ -231,6 +281,16 @@ public final class ThreadMXBeanImpl return SystemProperties.getProperty(CURRENT_THREAD_TIME_SUPPORT) != null; } + public boolean isObjectMonitorUsageSupported() + { + return SystemProperties.getProperty(MONITOR_SUPPORT) != null; + } + + public boolean isSynchronizerUsageSupported() + { + return SystemProperties.getProperty(SYNCHRONIZER_SUPPORT) != null; + } + public boolean isThreadContentionMonitoringEnabled() { if (isThreadContentionMonitoringSupported()) diff --git a/libjava/classpath/gnu/java/locale/LocaleHelper.java b/libjava/classpath/gnu/java/locale/LocaleHelper.java index cec0147179f..4fefd163979 100644 --- a/libjava/classpath/gnu/java/locale/LocaleHelper.java +++ b/libjava/classpath/gnu/java/locale/LocaleHelper.java @@ -55,105 +55,44 @@ import java.util.ResourceBundle; public class LocaleHelper { /** - * This method is used by the localized name lookup methods to retrieve - * the localized name of a particular piece of locale data. - * If the display name can not be localized to the supplied - * locale, it will fall back on other output in the following order: - * - * <ul> - * <li>the localized name in the default locale</li> - * <li>the localized name in English (optional)</li> - * <li>the localized name in the root locale bundle (optional)</li> - * <li>the localized input string</li> - * </ul> * <p> - * If the supplied key is merely the empty string, then the empty string is - * returned. + * This method is used by the localized name lookup methods to + * retrieve the next locale to try. The next locale is derived + * from the supplied locale by applying the first applicable + * rule from the following: + * </p> + * <ol> + * <li>If the variant contains a <code>'_'</code>, then + * this and everything following it is trimmed.</li> + * <li>If the variant is non-empty, it is converted to + * an empty string.</li> + * <li>If the country is non-empty, it is converted to + * an empty string.</li> + * <li>If the language is non-empty, it is converted to + * an empty string (forming {@link java.util.Locale#ROOT})</li> + * </ol> + * <p> + * The base fallback locale is {@link java.util.Locale#ROOT}. * </p> * - * @param inLocale the locale to use for formatting the display string. - * @param key the locale data used as a key to the localized lookup tables. - * @param name the name of the hashtable containing the localized data. - * @param checkEnglish true if the method should fall back on data - * from the English locale. - * @param checkRoot true if the method should fall back on data from the - * unlocalized root locale. - * @return a <code>String</code>, hopefully containing the localized - * variant of the input data. - * @throws NullPointerException if <code>inLocale</code> is null. + * @param locale the locale for which a localized piece of + * data could not be obtained. + * @return the next fallback locale to try. */ - public static String getLocalizedString(Locale inLocale, String key, - String name, boolean checkEnglish, - boolean checkRoot) + public static Locale getFallbackLocale(Locale locale) { - String localizedString; - String property; - - if (key.equals("")) - return ""; - property = name + "." + key; - /* Localize to inLocale */ - try - { - localizedString = - ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", - inLocale).getString(property); - } - catch (MissingResourceException exception) - { - localizedString = null; - } - /* Localize to default locale */ - if (localizedString == null) - { - try - { - ResourceBundle bundle; - - bundle = - ResourceBundle.getBundle("gnu.java.locale.LocaleInformation"); - localizedString = bundle.getString(property); - } - catch (MissingResourceException exception) - { - localizedString = null; - } - } - /* Localize to English */ - if (localizedString == null && checkEnglish) - { - try - { - localizedString = - ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", - Locale.ENGLISH).getString(property); - } - catch (MissingResourceException exception) - { - localizedString = null; - } - } - /* Return unlocalized version */ - if (localizedString == null && checkRoot) - { - try - { - localizedString = - ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", - new Locale("","","") - ).getString(property); - } - catch (MissingResourceException exception) - { - localizedString = null; - } - } - /* Return original input string */ - if (localizedString == null) - { - localizedString = key; - } - return localizedString; + String language = locale.getLanguage(); + String country = locale.getCountry(); + String variant = locale.getVariant(); + int uscore = variant.indexOf('_'); + if (uscore != -1) + return new Locale(language, country, + variant.substring(0, uscore)); + if (!variant.isEmpty()) + return new Locale(language, country, ""); + if (!country.isEmpty()) + return new Locale(language, "", ""); + return Locale.ROOT; } /** diff --git a/libjava/classpath/gnu/java/math/Fixed.java b/libjava/classpath/gnu/java/math/Fixed.java new file mode 100644 index 00000000000..e0284c329b9 --- /dev/null +++ b/libjava/classpath/gnu/java/math/Fixed.java @@ -0,0 +1,207 @@ +/* Fixed.java -- Utility methods for fixed point arithmetics + 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.math; + +/** + * Utility methods for fixed point arithmetics. + */ +public final class Fixed +{ + + /** + * Private constructor to avoid instantiation. + */ + private Fixed() + { + // Forbidden constructor. + } + + /** + * Divides two fixed point values with <code>n</code> digits. + * + * @param n the number of digits + * @param a the first operand as fixed point value + * @param b the second operand as fixed point value + * + * @return <code>a / b</code> as fixed point value + */ + public static int div(int n, int a, int b) + { + return (int) ((((long) a) << n) / b); + } + + /** + * Multiplies two fixed point values with <code>n</code> digits. + * + * @param n the number of digits + * @param a the first operand as fixed point value + * @param b the second operand as fixed point value + * + * @return <code>a * b</code> as fixed point value + */ + public static int mul(int n, int a, int b) + { + return (int) ((((long) a) * b) >> n); + } + + /** + * Returns the ceiling value of a fixed point value <code>a</code> with + * the <code>n</code> digits. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return <code>ceil(a)</code> as fixed point value + */ + public static int ceil(int n, int a) + { + return (a + (1 << n - 1)) & -(1 << n); + } + + /** + * Returns the floor value of a fixed point value <code>a</code> with + * <code>n</code> digits. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return <code>floor(a)</code> as fixed point value + */ + public static int floor(int n, int a) + { + return a & -(1 << n); + } + + /** + * Returns the round value of a fixed point value <code>a</code> with + * the <code>n</code> digits. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return <code>round(a)</code> as fixed point value + */ + public static int round(int n, int a) + { + return (a + (1 << (n - 1))) & -(1 << n); + } + + /** + * Returns the fixed point value <code>a</code> with <code>n</code> digits + * as float. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the float value of <code>a</code> + */ + public static float floatValue(int n, int a) + { + return ((float) a) / (1 << n); + } + + /** + * Returns the fixed point value <code>a</code> with <code>n</code> digits + * as double. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the double value of <code>a</code> + */ + public static double doubleValue(int n, int a) + { + return ((double) a) / (1 << n); + } + + /** + * Returns the fixed point value that corresponds to the specified float + * value <code>a</code> with <code>n</code> digits. + * + * @param n the number of digits + * @param a the float value + * + * @return the fixed point value + */ + public static int fixedValue(int n, float a) + { + return (int) (a * (1 << n)); + } + + /** + * Returns the fixed point value that corresponds to the specified double + * value <code>a</code> with <code>n</code> digits. + * + * @param n the number of digits + * @param a the double value + * + * @return the fixed point value + */ + public static int fixedValue(int n, double a) + { + return (int) (a * (1 << n)); + } + + /** + * Returns the integer value of the specified fixed point value + * <code>a</code>. This simply cuts of the digits (== floor(a)). + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the integer value + */ + public static int intValue(int n, int a) + { + return a >> n; + } + + /** + * Returns a fixed point decimal as rounded integer value. + * + * @param n the number of digits + * @param a the fixed point number + * + * @return the fixed point decimal as rounded integer value + */ + public static int roundIntValue(int n, int a) + { + return (a + (1 << (n - 1))) >> n; + } +} diff --git a/libjava/classpath/gnu/java/net/BASE64.java b/libjava/classpath/gnu/java/net/BASE64.java deleted file mode 100644 index 901aa0c35fc..00000000000 --- a/libjava/classpath/gnu/java/net/BASE64.java +++ /dev/null @@ -1,190 +0,0 @@ -/* BASE.java -- - Copyright (C) 2003, 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.net; - -/** - * Encodes and decodes text according to the BASE64 encoding. - * - * @author Chris Burdess (dog@gnu.org) - */ -public final class BASE64 -{ - private static final byte[] src = { - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, - 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, - 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, - 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x2b, 0x2f - }; - - private static final byte[] dst; - static - { - dst = new byte[0x100]; - for (int i = 0x0; i < 0xff; i++) - { - dst[i] = -1; - } - for (int i = 0; i < src.length; i++) - { - dst[src[i]] = (byte) i; - } - } - - private BASE64() - { - } - - /** - * Encode the specified byte array using the BASE64 algorithm. - * - * @param bs the source byte array - */ - public static byte[] encode(byte[] bs) - { - int si = 0, ti = 0; // source/target array indices - byte[] bt = new byte[((bs.length + 2) * 4) / 3]; // target byte array - for (; si < bs.length; si += 3) - { - int buflen = bs.length - si; - if (buflen == 1) - { - byte b = bs[si]; - int i = 0; - bt[ti++] = src[b >>> 2 & 0x3f]; - bt[ti++] = src[(b << 4 & 0x30) + (i >>> 4 & 0xf)]; - } - else if (buflen == 2) - { - byte b1 = bs[si], b2 = bs[si + 1]; - int i = 0; - bt[ti++] = src[b1 >>> 2 & 0x3f]; - bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)]; - bt[ti++] = src[(b2 << 2 & 0x3c) + (i >>> 6 & 0x3)]; - } - else - { - byte b1 = bs[si], b2 = bs[si + 1], b3 = bs[si + 2]; - bt[ti++] = src[b1 >>> 2 & 0x3f]; - bt[ti++] = src[(b1 << 4 & 0x30) + (b2 >>> 4 & 0xf)]; - bt[ti++] = src[(b2 << 2 & 0x3c) + (b3 >>> 6 & 0x3)]; - bt[ti++] = src[b3 & 0x3f]; - } - } - if (ti < bt.length) - { - byte[] tmp = new byte[ti]; - System.arraycopy(bt, 0, tmp, 0, ti); - bt = tmp; - } - /*while (ti < bt.length) - { - bt[ti++] = 0x3d; - }*/ - return bt; - } - - /** - * Decode the specified byte array using the BASE64 algorithm. - * - * @param bs the source byte array - */ - public static byte[] decode(byte[] bs) - { - int srclen = bs.length; - while (srclen > 0 && bs[srclen - 1] == 0x3d) - { - srclen--; /* strip padding character */ - } - byte[] buffer = new byte[srclen]; - int buflen = 0; - int si = 0; - int len = srclen - si; - while (len > 0) - { - byte b0 = dst[bs[si++] & 0xff]; - byte b2 = dst[bs[si++] & 0xff]; - buffer[buflen++] = (byte) (b0 << 2 & 0xfc | b2 >>> 4 & 0x3); - if (len > 2) - { - b0 = b2; - b2 = dst[bs[si++] & 0xff]; - buffer[buflen++] = (byte) (b0 << 4 & 0xf0 | b2 >>> 2 & 0xf); - if (len > 3) - { - b0 = b2; - b2 = dst[bs[si++] & 0xff]; - buffer[buflen++] = (byte) (b0 << 6 & 0xc0 | b2 & 0x3f); - } - } - len = srclen - si; - } - byte[] bt = new byte[buflen]; - System.arraycopy(buffer, 0, bt, 0, buflen); - return bt; - } - - public static void main(String[] args) - { - boolean decode = false; - for (int i = 0; i < args.length; i++) - { - if (args[i].equals("-d")) - { - decode = true; - } - else - { - try - { - byte[] in = args[i].getBytes("US-ASCII"); - byte[] out = decode ? decode(in) : encode(in); - System.out.println(args[i] + " = " + - new String(out, "US-ASCII")); - } - catch (java.io.UnsupportedEncodingException e) - { - e.printStackTrace(System.err); - } - } - } - } -} diff --git a/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java b/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java index bb0a7ce5d21..e3d1b8e5a96 100644 --- a/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java +++ b/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java @@ -81,8 +81,8 @@ public class DefaultContentHandlerFactory implements ContentHandlerFactory "image/x-xpixmap" }; - private static HashSet imageTypes - = new HashSet(Arrays.asList(known_image_types)); + private static HashSet<String> imageTypes + = new HashSet<String>(Arrays.asList(known_image_types)); public ContentHandler createContentHandler(String mimeType) { diff --git a/libjava/classpath/gnu/java/net/GetLocalHostAction.java b/libjava/classpath/gnu/java/net/GetLocalHostAction.java index 7483b025773..fa76015552b 100644 --- a/libjava/classpath/gnu/java/net/GetLocalHostAction.java +++ b/libjava/classpath/gnu/java/net/GetLocalHostAction.java @@ -48,9 +48,9 @@ import java.security.PrivilegedAction; * @author Chris Burdess (dog@gnu.org) */ public class GetLocalHostAction - implements PrivilegedAction + implements PrivilegedAction<InetAddress> { - public Object run() + public InetAddress run() { try { diff --git a/libjava/classpath/gnu/java/net/HeaderFieldHelper.java b/libjava/classpath/gnu/java/net/HeaderFieldHelper.java index 0fb8d953d21..a8d13ce153b 100644 --- a/libjava/classpath/gnu/java/net/HeaderFieldHelper.java +++ b/libjava/classpath/gnu/java/net/HeaderFieldHelper.java @@ -49,8 +49,8 @@ import java.util.Vector; */ public class HeaderFieldHelper { - private Vector headerFieldKeys; - private Vector headerFieldValues; + private Vector<String> headerFieldKeys; + private Vector<String> headerFieldValues; public HeaderFieldHelper() { @@ -59,8 +59,8 @@ public class HeaderFieldHelper public HeaderFieldHelper (int size) { - headerFieldKeys = new Vector (size); - headerFieldValues = new Vector (size); + headerFieldKeys = new Vector<String> (size); + headerFieldValues = new Vector<String> (size); } public void addHeaderField (String key, String value) @@ -75,7 +75,7 @@ public class HeaderFieldHelper try { - key = (String) headerFieldKeys.elementAt (index); + key = headerFieldKeys.elementAt (index); } catch (ArrayIndexOutOfBoundsException e) { @@ -90,7 +90,7 @@ public class HeaderFieldHelper try { - value = (String) headerFieldValues.elementAt (index); + value = headerFieldValues.elementAt (index); } catch (ArrayIndexOutOfBoundsException e) { @@ -105,8 +105,7 @@ public class HeaderFieldHelper try { - value = (String) headerFieldValues.elementAt - (headerFieldKeys.indexOf(key)); + value = headerFieldValues.elementAt(headerFieldKeys.indexOf(key)); } catch (ArrayIndexOutOfBoundsException e) { @@ -115,9 +114,9 @@ public class HeaderFieldHelper return value; } - public Map getHeaderFields() + public Map<String, String> getHeaderFields() { - HashMap headers = new HashMap(); + HashMap<String, String> headers = new HashMap<String, String>(); int max = headerFieldKeys.size(); for (int index = 0; index < max; index++) diff --git a/libjava/classpath/gnu/java/net/IndexListParser.java b/libjava/classpath/gnu/java/net/IndexListParser.java index 1165929fc35..2d90ceb6433 100644 --- a/libjava/classpath/gnu/java/net/IndexListParser.java +++ b/libjava/classpath/gnu/java/net/IndexListParser.java @@ -43,6 +43,7 @@ import java.io.InputStreamReader; import java.net.URL; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.Set; import java.util.jar.JarFile; /** @@ -70,7 +71,8 @@ public class IndexListParser double versionNumber; // Map each jar to the prefixes defined for the jar. // This is intentionally kept in insertion order. - LinkedHashMap prefixes = new LinkedHashMap(); + LinkedHashMap<URL, Set<String>> prefixes + = new LinkedHashMap<URL, Set<String>>(); /** * Parses the given jarfile's INDEX.LIST file if it exists. @@ -107,7 +109,7 @@ public class IndexListParser while ((line = br.readLine()) != null) { URL jarURL = new URL(baseURL, line); - HashSet values = new HashSet(); + HashSet<String> values = new HashSet<String>(); // Read the names in the section. while ((line = br.readLine()) != null) @@ -174,7 +176,7 @@ public class IndexListParser * * @return an map of all the headers, or null if no INDEX.LIST was found */ - public LinkedHashMap getHeaders() + public LinkedHashMap<URL, Set<String>> getHeaders() { return prefixes; } diff --git a/libjava/classpath/gnu/java/net/loader/JarURLLoader.java b/libjava/classpath/gnu/java/net/loader/JarURLLoader.java index 9385760d547..40194be799a 100644 --- a/libjava/classpath/gnu/java/net/loader/JarURLLoader.java +++ b/libjava/classpath/gnu/java/net/loader/JarURLLoader.java @@ -32,7 +32,7 @@ public final class JarURLLoader extends URLLoader // Base jar: url for all resources loaded from jar. final URL baseJarURL; // The "Class-Path" attribute of this Jar's manifest. - ArrayList classPath; + ArrayList<URLLoader> classPath; // If not null, a mapping from INDEX.LIST for this jar only. // This is a set of all prefixes and top-level files that // ought to be available in this jar. @@ -90,20 +90,20 @@ public final class JarURLLoader extends URLLoader IndexListParser parser = new IndexListParser(jarfile, baseJarURL, baseURL); - LinkedHashMap indexMap = parser.getHeaders(); + LinkedHashMap<URL, Set<String>> indexMap = parser.getHeaders(); if (indexMap != null) { // Note that the index also computes // the resulting Class-Path -- there are jars out there // where the index lists some required jars which do // not appear in the Class-Path attribute in the manifest. - this.classPath = new ArrayList(); - Iterator it = indexMap.entrySet().iterator(); + this.classPath = new ArrayList<URLLoader>(); + Iterator<Map.Entry<URL, Set<String>>> it = indexMap.entrySet().iterator(); while (it.hasNext()) { - Map.Entry entry = (Map.Entry) it.next(); - URL subURL = (URL) entry.getKey(); - Set prefixes = (Set) entry.getValue(); + Map.Entry<URL, Set<String>> entry = it.next(); + URL subURL = entry.getKey(); + Set<String> prefixes = entry.getValue(); if (subURL.equals(baseURL)) this.indexSet = prefixes; else @@ -127,7 +127,7 @@ public final class JarURLLoader extends URLLoader = attributes.getValue(Attributes.Name.CLASS_PATH)) != null)) { - this.classPath = new ArrayList(); + this.classPath = new ArrayList<URLLoader>(); StringTokenizer st = new StringTokenizer(classPathString, " "); while (st.hasMoreElements ()) { @@ -144,7 +144,7 @@ public final class JarURLLoader extends URLLoader cache, factory, subURL, subURL); this.classPath.add(subLoader); - ArrayList extra = subLoader.getClassPath(); + ArrayList<URLLoader> extra = subLoader.getClassPath(); if (extra != null) this.classPath.addAll(extra); } @@ -208,7 +208,7 @@ public final class JarURLLoader extends URLLoader } } - public ArrayList getClassPath() + public ArrayList<URLLoader> getClassPath() { return classPath; } diff --git a/libjava/classpath/gnu/java/net/loader/URLLoader.java b/libjava/classpath/gnu/java/net/loader/URLLoader.java index d073c54296a..5228bcac96d 100644 --- a/libjava/classpath/gnu/java/net/loader/URLLoader.java +++ b/libjava/classpath/gnu/java/net/loader/URLLoader.java @@ -140,7 +140,7 @@ public abstract class URLLoader * Return a list of new URLLoader objects representing any * class path entries added by this container. */ - public ArrayList getClassPath() + public ArrayList<URLLoader> getClassPath() { return null; } diff --git a/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java b/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java index 295a15d2b53..b7b8bf12bf1 100644 --- a/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java +++ b/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java @@ -51,7 +51,8 @@ public class URLStreamHandlerCache * private protocol handler cache (also a HashMap), so we can avoid * creating handlers each time the same protocol comes. */ - private HashMap factoryCache = new HashMap(5); + private HashMap<URLStreamHandlerFactory, HashMap<String, URLStreamHandler>> factoryCache + = new HashMap<URLStreamHandlerFactory, HashMap<String, URLStreamHandler>>(5); public URLStreamHandlerCache() { @@ -62,7 +63,7 @@ public class URLStreamHandlerCache // Since we only support three protocols so far, 5 is enough // for cache initial size. if (factory != null && factoryCache.get(factory) == null) - factoryCache.put(factory, new HashMap(5)); + factoryCache.put(factory, new HashMap<String, URLStreamHandler>(5)); } public synchronized URLStreamHandler get(URLStreamHandlerFactory factory, @@ -71,8 +72,8 @@ public class URLStreamHandlerCache if (factory == null) return null; // Check if there're handler for the same protocol in cache. - HashMap cache = (HashMap) factoryCache.get(factory); - URLStreamHandler handler = (URLStreamHandler) cache.get(protocol); + HashMap<String, URLStreamHandler> cache = factoryCache.get(factory); + URLStreamHandler handler = cache.get(protocol); if (handler == null) { // Add it to cache. diff --git a/libjava/classpath/gnu/java/net/local/LocalServerSocket.java b/libjava/classpath/gnu/java/net/local/LocalServerSocket.java index 15163f243a8..9d8a6ccdf32 100644 --- a/libjava/classpath/gnu/java/net/local/LocalServerSocket.java +++ b/libjava/classpath/gnu/java/net/local/LocalServerSocket.java @@ -44,7 +44,6 @@ 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 { diff --git a/libjava/classpath/gnu/java/net/local/LocalSocket.java b/libjava/classpath/gnu/java/net/local/LocalSocket.java index b262c794e3d..92acc65bb62 100644 --- a/libjava/classpath/gnu/java/net/local/LocalSocket.java +++ b/libjava/classpath/gnu/java/net/local/LocalSocket.java @@ -46,7 +46,6 @@ 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; diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java index f5317d479bc..fd79019183a 100644 --- a/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java @@ -1139,7 +1139,7 @@ public class FTPConnection * @param pathname the directory pathname, or null * @return a list of filenames(strings) */ - public List nameList(String pathname) + public List<String> nameList(String pathname) throws IOException { if (dtp == null || transferMode == MODE_STREAM) @@ -1164,7 +1164,7 @@ public class FTPConnection in = new BufferedInputStream(in); in = new CRLFInputStream(in); // TODO ensure that TYPE is correct LineInputStream li = new LineInputStream(in); - List ret = new ArrayList(); + ArrayList<String> ret = new ArrayList<String>(); for (String line = li.readLine(); line != null; line = li.readLine()) diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java index f937e51f606..cfad5a7c1a6 100644 --- a/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java @@ -50,7 +50,9 @@ import java.net.InetAddress; import java.net.URL; import java.net.URLConnection; import java.security.AccessController; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -112,7 +114,7 @@ public class FTPURLConnection { username = "anonymous"; GetLocalHostAction a = new GetLocalHostAction(); - InetAddress localhost =(InetAddress) AccessController.doPrivileged(a); + InetAddress localhost = AccessController.doPrivileged(a); password = SystemProperties.getProperty("user.name") + "@" + ((localhost == null) ? "localhost" : localhost.getHostName()); } @@ -232,9 +234,9 @@ public class FTPURLConnection return null; } - public Map getRequestProperties() + public Map<String, List<String>> getRequestProperties() { - Map map = new HashMap(); + Map<String, List<String>> map = new HashMap<String, List<String>>(); addRequestPropertyValue(map, "passive"); addRequestPropertyValue(map, "representationType"); addRequestPropertyValue(map, "fileStructure"); @@ -242,10 +244,13 @@ public class FTPURLConnection return map; } - private void addRequestPropertyValue(Map map, String key) + private void addRequestPropertyValue(Map<String, List<String>> map, + String key) { String value = getRequestProperty(key); - map.put(key, value); + ArrayList<String> l = new ArrayList<String>(); + l.add(value); + map.put(key, l); } public void setRequestProperty(String key, String value) diff --git a/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java b/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java index 9870412f2da..8abef71d521 100644 --- a/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java +++ b/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java @@ -58,10 +58,6 @@ import java.net.ProtocolException; public class ChunkedInputStream extends InputStream { - - private static final byte CR = 0x0d; - private static final byte LF = 0x0a; - Headers headers; /** The underlying stream. */ diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java index 3956d2aba3a..9d19bfbdba4 100644 --- a/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java +++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java @@ -129,7 +129,7 @@ public class HTTPConnection */ protected int minorVersion; - private final List handshakeCompletedListeners; + private final List<HandshakeCompletedListener> handshakeCompletedListeners; /** * The socket this connection communicates on. @@ -154,7 +154,7 @@ public class HTTPConnection /** * Nonce values seen by this connection. */ - private Map nonceCounts; + private Map<String, Integer> nonceCounts; /** * The cookie manager for this connection. @@ -244,7 +244,8 @@ public class HTTPConnection this.connectionTimeout = connectionTimeout; this.timeout = timeout; majorVersion = minorVersion = 1; - handshakeCompletedListeners = new ArrayList(2); + handshakeCompletedListeners + = new ArrayList<HandshakeCompletedListener>(2); } /** @@ -357,7 +358,8 @@ public class HTTPConnection /** * The pool */ - final LinkedList connectionPool = new LinkedList(); + final LinkedList<HTTPConnection> connectionPool + = new LinkedList<HTTPConnection>(); /** * Maximum size of the pool. @@ -857,7 +859,7 @@ public class HTTPConnection { return 0; } - return((Integer) nonceCounts.get(nonce)).intValue(); + return nonceCounts.get(nonce).intValue(); } /** @@ -868,7 +870,7 @@ public class HTTPConnection int current = getNonceCount(nonce); if (nonceCounts == null) { - nonceCounts = new HashMap(); + nonceCounts = new HashMap<String, Integer>(); } nonceCounts.put(nonce, new Integer(current + 1)); } diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java index 6c926b72fb4..b31f426695f 100644 --- a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java +++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java @@ -50,11 +50,11 @@ import java.net.URL; import java.security.cert.Certificate; import java.util.Collections; import java.util.Date; +import java.util.List; import java.util.Map; import javax.net.ssl.HandshakeCompletedEvent; import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSocketFactory; @@ -170,7 +170,8 @@ public class HTTPURLConnection if (secure) { SSLSocketFactory factory = getSSLSocketFactory(); - HostnameVerifier verifier = getHostnameVerifier(); + // FIXME: use the verifier + // HostnameVerifier verifier = getHostnameVerifier(); if (factory != null) { connection.setSSLSocketFactory(factory); @@ -428,12 +429,12 @@ public class HTTPURLConnection return requestHeaders.getValue(key); } - public Map getRequestProperties() + public Map<String, List<String>> getRequestProperties() { if (connected) throw new IllegalStateException("Already connected"); - Map m = requestHeaders.getAsMap(); + Map<String, List<String>> m = requestHeaders.getAsMap(); return Collections.unmodifiableMap(m); } @@ -509,7 +510,7 @@ public class HTTPURLConnection return errorSink; } - public Map getHeaderFields() + public Map<String,List<String>> getHeaderFields() { if (!connected) { @@ -522,7 +523,7 @@ public class HTTPURLConnection return null; } } - Map m = response.getHeaders().getAsMap(); + Map<String,List<String>> m = response.getHeaders().getAsMap(); m.put(null, Collections.singletonList(getStatusLine(response))); return Collections.unmodifiableMap(m); } diff --git a/libjava/classpath/gnu/java/net/protocol/http/Headers.java b/libjava/classpath/gnu/java/net/protocol/http/Headers.java index a793bbd9728..c8736bbac8f 100644 --- a/libjava/classpath/gnu/java/net/protocol/http/Headers.java +++ b/libjava/classpath/gnu/java/net/protocol/http/Headers.java @@ -42,6 +42,7 @@ import gnu.java.net.LineInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.Iterable; import java.text.DateFormat; import java.text.ParseException; import java.util.ArrayList; @@ -49,6 +50,7 @@ import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -60,12 +62,13 @@ import java.util.Map; * @author Chris Burdess (dog@gnu.org) * @author David Daney (ddaney@avtrex.com) */ -class Headers +class Headers implements Iterable<Headers.HeaderElement> { /** * A list of HeaderElements */ - private final ArrayList headers = new ArrayList(); + private final ArrayList<HeaderElement> headers + = new ArrayList<HeaderElement>(); /** * The HTTP dateformat used to parse date header fields. @@ -102,7 +105,7 @@ class Headers * * @return the Iterator. */ - Iterator iterator() + public Iterator<HeaderElement> iterator() { return headers.iterator(); } @@ -118,7 +121,7 @@ class Headers { for (int i = headers.size() - 1; i >= 0; i--) { - HeaderElement e = (HeaderElement)headers.get(i); + HeaderElement e = headers.get(i); if (e.name.equalsIgnoreCase(header)) { return e.value; @@ -219,7 +222,7 @@ class Headers { for (int i = headers.size() - 1; i >= 0; i--) { - HeaderElement e = (HeaderElement)headers.get(i); + HeaderElement e = headers.get(i); if (e.name.equalsIgnoreCase(name)) { e.value = value; @@ -240,9 +243,9 @@ class Headers */ public void putAll(Headers o) { - for (Iterator it = o.iterator(); it.hasNext(); ) + for (Iterator<HeaderElement> it = o.iterator(); it.hasNext(); ) { - HeaderElement e = (HeaderElement)it.next(); + HeaderElement e = it.next(); remove(e.name); addValue(e.name, e.value); } @@ -256,9 +259,9 @@ class Headers */ public void remove(String name) { - for (Iterator it = headers.iterator(); it.hasNext(); ) + for (Iterator<HeaderElement> it = headers.iterator(); it.hasNext(); ) { - HeaderElement e = (HeaderElement)it.next(); + HeaderElement e = it.next(); if (e.name.equalsIgnoreCase(name)) it.remove(); } @@ -358,26 +361,26 @@ class Headers * * @return a Map containing all the headers. */ - public Map getAsMap() + public Map<String,List<String>> getAsMap() { - LinkedHashMap m = new LinkedHashMap(); - for (Iterator it = headers.iterator(); it.hasNext(); ) + LinkedHashMap<String,List<String>> m = new LinkedHashMap<String,List<String>>(); + for (Iterator<HeaderElement> it = headers.iterator(); it.hasNext(); ) { - HeaderElement e = (HeaderElement)it.next(); - ArrayList l = (ArrayList)m.get(e.name); + HeaderElement e = it.next(); + ArrayList<String> l = (ArrayList<String>)m.get(e.name); if (l == null) { - l = new ArrayList(1); + l = new ArrayList<String>(1); l.add(e.value); m.put(e.name, l); } else l.add(0, e.value); } - for (Iterator it = m.entrySet().iterator(); it.hasNext(); ) + for (Iterator<Map.Entry<String,List<String>>> it = m.entrySet().iterator(); it.hasNext(); ) { - Map.Entry me = (Map.Entry)it.next(); - ArrayList l = (ArrayList)me.getValue(); + Map.Entry<String,List<String>> me = it.next(); + List<String> l = me.getValue(); me.setValue(Collections.unmodifiableList(l)); } return m; @@ -397,7 +400,7 @@ class Headers if (i >= headers.size() || i < 0) return null; - return ((HeaderElement)headers.get(i)).name; + return headers.get(i).name; } /** @@ -414,8 +417,6 @@ class Headers if (i >= headers.size() || i < 0) return null; - return ((HeaderElement)headers.get(i)).value; + return headers.get(i).value; } - } - diff --git a/libjava/classpath/gnu/java/net/protocol/http/Request.java b/libjava/classpath/gnu/java/net/protocol/http/Request.java index cd9d7ea4423..06a779f3311 100644 --- a/libjava/classpath/gnu/java/net/protocol/http/Request.java +++ b/libjava/classpath/gnu/java/net/protocol/http/Request.java @@ -1,5 +1,5 @@ /* Request.java -- - Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,8 +38,8 @@ exception statement from your version. */ package gnu.java.net.protocol.http; -import gnu.java.net.BASE64; import gnu.java.net.LineInputStream; +import gnu.java.util.Base64; import java.io.IOException; import java.io.InputStream; @@ -96,7 +96,7 @@ public class Request /** * Map of response header handlers. */ - protected Map responseHeaderHandlers; + protected Map<String, ResponseHeaderHandler> responseHeaderHandlers; /** * The authenticator. @@ -121,7 +121,7 @@ public class Request this.method = method; this.path = path; requestHeaders = new Headers(); - responseHeaderHandlers = new HashMap(); + responseHeaderHandlers = new HashMap<String, ResponseHeaderHandler>(); } /** @@ -302,9 +302,8 @@ public class Request String line = method + ' ' + requestUri + ' ' + version + CRLF; out.write(line.getBytes(US_ASCII)); // Request headers - for (Iterator i = requestHeaders.iterator(); i.hasNext(); ) + for (Headers.HeaderElement elt : requestHeaders) { - Headers.HeaderElement elt = (Headers.HeaderElement)i.next(); line = elt.name + HEADER_SEP + elt.value + CRLF; out.write(line.getBytes(US_ASCII)); } @@ -439,9 +438,8 @@ public class Request void notifyHeaderHandlers(Headers headers) { - for (Iterator i = headers.iterator(); i.hasNext(); ) + for (Headers.HeaderElement entry : headers) { - Headers.HeaderElement entry = (Headers.HeaderElement) i.next(); // Handle Set-Cookie if ("Set-Cookie".equalsIgnoreCase(entry.name)) handleSetCookie(entry.value); @@ -461,7 +459,6 @@ public class Request throws IOException { long contentLength = -1; - Headers trailer = null; // Persistent connections are the default in HTTP/1.1 boolean doClose = "close".equalsIgnoreCase(getHeader("Connection")) || @@ -532,7 +529,7 @@ public class Request Credentials creds = authenticator.getCredentials(realm, attempts); String userPass = creds.getUsername() + ':' + creds.getPassword(); byte[] b_userPass = userPass.getBytes("US-ASCII"); - byte[] b_encoded = BASE64.encode(b_userPass); + byte[] b_encoded = Base64.encode(b_userPass).getBytes("US-ASCII"); String authorization = scheme + " " + new String(b_encoded, "US-ASCII"); setHeader("Authorization", authorization); diff --git a/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java index 8947471885c..fe05ba09e5e 100644 --- a/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java +++ b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java @@ -1,5 +1,5 @@ /* CookieManager.java -- - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -42,7 +42,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; -import java.util.List; import java.util.Map; /** @@ -59,23 +58,23 @@ public class SimpleCookieManager * The cookie cache. * This is a dictionary mapping domains to maps of cookies by name. */ - protected Map cookies; + protected Map<String, Map<String, Cookie>> cookies; /** * Constructor. */ public SimpleCookieManager() { - cookies = new HashMap(); + cookies = new HashMap<String, Map<String, Cookie>>(); } public void setCookie(Cookie cookie) { String domain = cookie.getDomain(); - Map map =(Map) cookies.get(domain); + Map<String, Cookie> map = cookies.get(domain); if (map == null) { - map = new HashMap(); + map = new HashMap<String, Cookie>(); cookies.put(domain, map); } String name = cookie.getName(); @@ -84,7 +83,7 @@ public class SimpleCookieManager public Cookie[] getCookies(String host, boolean secure, String path) { - List matches = new ArrayList(); + ArrayList<Cookie> matches = new ArrayList<Cookie>(); Date now = new Date(); if (Character.isLetter(host.charAt(0))) { @@ -102,17 +101,16 @@ public class SimpleCookieManager return ret; } - private void addCookies(List matches, String domain, boolean secure, - String path, Date now) + private void addCookies(ArrayList<Cookie> matches, String domain, + boolean secure, String path, Date now) { - Map map = (Map) cookies.get(domain); + Map<String, Cookie> map = cookies.get(domain); if (map != null) { - List expired = new ArrayList(); - for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) + ArrayList<String> expired = new ArrayList<String>(); + for (Map.Entry<String, Cookie> entry : map.entrySet()) { - Map.Entry entry = (Map.Entry) i.next(); - Cookie cookie = (Cookie) entry.getValue(); + Cookie cookie = entry.getValue(); Date expires = cookie.getExpiryDate(); if (expires != null && expires.before(now)) { @@ -129,7 +127,7 @@ public class SimpleCookieManager } } // Good housekeeping - for (Iterator i = expired.iterator(); i.hasNext(); ) + for (Iterator<String> i = expired.iterator(); i.hasNext(); ) { map.remove(i.next()); } diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Connection.java b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java index f99806ae42d..386aacef63e 100644 --- a/libjava/classpath/gnu/java/net/protocol/jar/Connection.java +++ b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java @@ -76,7 +76,8 @@ public final class Connection extends JarURLConnection public static class JarFileCache { - private static Hashtable cache = new Hashtable(); + private static Hashtable<URL, JarFile> cache + = new Hashtable<URL, JarFile>(); private static final int READBUFSIZE = 4*1024; public static synchronized JarFile get (URL url, boolean useCaches) @@ -85,7 +86,7 @@ public final class Connection extends JarURLConnection JarFile jf; if (useCaches) { - jf = (JarFile) cache.get (url); + jf = cache.get (url); if (jf != null) return jf; } diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java index 7c09766a557..c57d0a36016 100644 --- a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java +++ b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java @@ -164,7 +164,7 @@ public class Handler extends URLStreamHandler if (jar_path.indexOf("/.") < 0) return url_string; - ArrayList tokens = new ArrayList(); + ArrayList<String> tokens = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(jar_path, "/"); while (st.hasMoreTokens()) { @@ -183,7 +183,7 @@ public class Handler extends URLStreamHandler StringBuffer path = new StringBuffer(url_string.length()); path.append(url_string.substring(0, jar_stop + 1)); - Iterator it = tokens.iterator(); + Iterator<String> it = tokens.iterator(); while (it.hasNext()) path.append('/').append(it.next()); diff --git a/libjava/classpath/gnu/java/nio/ChannelInputStream.java b/libjava/classpath/gnu/java/nio/ChannelInputStream.java index 675a62f3d88..f56536d65ad 100644 --- a/libjava/classpath/gnu/java/nio/ChannelInputStream.java +++ b/libjava/classpath/gnu/java/nio/ChannelInputStream.java @@ -59,6 +59,16 @@ public final class ChannelInputStream extends InputStream this.ch = ch; } + public int read(byte[] buf, int off, int len) throws IOException + { + if (ch instanceof SelectableChannel + && (! ((SelectableChannel) ch).isBlocking())) + throw new IllegalBlockingModeException(); + + ByteBuffer b = ByteBuffer.wrap(buf, off, len); + return ch.read(b); + } + public int read() throws IOException { if (ch instanceof SelectableChannel @@ -74,6 +84,6 @@ public final class ChannelInputStream extends InputStream if (result == 0) throw new IOException("Could not read from channel"); - return buffer.get(0); + return buffer.get(0) & 0xff; } } diff --git a/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java index 56167b69ea8..0c509b985ff 100644 --- a/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java +++ b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java @@ -117,4 +117,5 @@ public class SelectorProviderImpl extends SelectorProvider { return new SocketChannelImpl (this); } + } diff --git a/libjava/classpath/gnu/java/nio/charset/ByteCharset.java b/libjava/classpath/gnu/java/nio/charset/ByteCharset.java index da0fdcbcdb3..e2025482956 100644 --- a/libjava/classpath/gnu/java/nio/charset/ByteCharset.java +++ b/libjava/classpath/gnu/java/nio/charset/ByteCharset.java @@ -115,8 +115,11 @@ abstract class ByteCharset extends Charset return CoderResult.OVERFLOW; } - if((c = lookup[(int) (b & 0xFF)]) == NONE); - // return CoderResult.unmappableForLength (1); + if((c = lookup[(int) (b & 0xFF)]) == NONE) + { + in.position (in.position () - 1); + return CoderResult.unmappableForLength (1); + } out.put (c); } diff --git a/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java b/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java index 033440d5da2..be7b4afe05d 100644 --- a/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java +++ b/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java @@ -148,6 +148,17 @@ public class EncodingHelper throw new UnsupportedEncodingException("Charset "+name+" not found."); } } + + /** + * Returns the default charset without throwing any exceptions. The default + * charset is UTF8. + * + * @return the default charset + */ + public static Charset getDefaultCharset() + { + return new UTF_8(); + } } diff --git a/libjava/classpath/gnu/java/security/util/Base64.java b/libjava/classpath/gnu/java/security/util/Base64.java deleted file mode 100644 index 9b2ae12dc27..00000000000 --- a/libjava/classpath/gnu/java/security/util/Base64.java +++ /dev/null @@ -1,349 +0,0 @@ -/* Base64.java -- - Copyright (C) 2003, 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.security.util; - -import gnu.java.security.Configuration; - -import java.io.UnsupportedEncodingException; -import java.util.logging.Logger; - -/** - * Most of this implementation is from Robert Harder's public domain Base64 - * code (version 1.4.1 available from <http://iharder.net/xmlizable>). - */ -public class Base64 -{ - private static final Logger log = Logger.getLogger(Base64.class.getName()); - - /** Maximum line length (76) of Base64 output. */ - private static final int MAX_LINE_LENGTH = 76; - - /** The new line character (\n) as one byte. */ - private static final byte NEW_LINE = (byte) '\n'; - - /** The equals sign (=) as a byte. */ - private static final byte EQUALS_SIGN = (byte) '='; - - private static final byte WHITE_SPACE_ENC = -5; // white space in encoding - - private static final byte EQUALS_SIGN_ENC = -1; // equals sign in encoding - - /** The 64 valid Base64 values. */ - private static final byte[] ALPHABET = { - (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', - (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', - (byte) 'S', (byte) 'T', (byte) 'U', (byte) 'V', (byte) 'W', (byte) 'X', - (byte) 'Y', (byte) 'Z', (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', - (byte) 'e', (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', (byte) 'p', - (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', (byte) 'v', - (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', (byte) '0', (byte) '1', - (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', - (byte) '8', (byte) '9', (byte) '+', (byte) '/' - }; - - /** - * Translates a Base64 value to either its 6-bit reconstruction value or a - * negative number indicating some other meaning. - */ - private static final byte[] DECODABET = { - -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9 // Decimal 123 - 126 - }; - - /** Trivial private ctor to enfore Singleton pattern. */ - private Base64() - { - super(); - } - - /** - * Encodes a byte array into Base64 notation. Equivalent to calling - * <code>encode(source, 0, source.length)</code>. - * - * @param src the data to convert. - */ - public static final String encode(final byte[] src) - { - return encode(src, 0, src.length, true); - } - - /** - * Encodes a byte array into Base64 notation. - * - * @param src the data to convert. - * @param off offset in array where conversion should begin. - * @param len length of data to convert. - * @param breakLines break lines at 80 characters or less. - */ - public static final String encode(final byte[] src, final int off, - final int len, final boolean breakLines) - { - final int len43 = len * 4 / 3; - final byte[] outBuff = new byte[len43 // Main 4:3 - + ((len % 3) > 0 ? 4 : 0) // Account for padding - + (breakLines ? (len43 / MAX_LINE_LENGTH) - : 0)]; // New lines - int d = 0; - int e = 0; - final int len2 = len - 2; - int lineLength = 0; - for (; d < len2; d += 3, e += 4) - { - encode3to4(src, d + off, 3, outBuff, e); - lineLength += 4; - if (breakLines && lineLength == MAX_LINE_LENGTH) - { - outBuff[e + 4] = NEW_LINE; - e++; - lineLength = 0; - } - } - if (d < len) // padding needed - { - encode3to4(src, d + off, len - d, outBuff, e); - e += 4; - } - return new String(outBuff, 0, e); - } - - /** - * Decodes data from Base64 notation. - * - * @param s the string to decode. - * @return the decoded data. - */ - public static final byte[] decode(final String s) - throws UnsupportedEncodingException - { - final byte[] bytes; - bytes = s.getBytes("US-ASCII"); - return decode(bytes, 0, bytes.length); - } - - /** - * Decodes Base64 content in byte array format and returns the decoded byte - * array. - * - * @param src the Base64 encoded data. - * @param off the offset of where to begin decoding. - * @param len the length of characters to decode. - * @return the decoded data. - * @throws IllegalArgumentException if <code>src</code> contains an illegal - * Base-64 character. - */ - public static byte[] decode(final byte[] src, final int off, final int len) - { - final int len34 = len * 3 / 4; - final byte[] outBuff = new byte[len34]; // Upper limit on size of output - int outBuffPosn = 0; - final byte[] b4 = new byte[4]; - int b4Posn = 0; - int i; - byte sbiCrop, sbiDecode; - for (i = off; i < off + len; i++) - { - sbiCrop = (byte) (src[i] & 0x7F); // Only the low seven bits - sbiDecode = DECODABET[sbiCrop]; - if (sbiDecode >= WHITE_SPACE_ENC) - { // White space, Equals sign or better - if (sbiDecode >= EQUALS_SIGN_ENC) - { - b4[b4Posn++] = sbiCrop; - if (b4Posn > 3) - { - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn); - b4Posn = 0; - // If that was the equals sign, break out of 'for' loop - if (sbiCrop == EQUALS_SIGN) - break; - } // end if: quartet built - } // end if: equals sign or better - } - throw new IllegalArgumentException("Illegal BASE-64 character at #" - + i + ": " + src[i] + "(decimal)"); - } - final byte[] result = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, result, 0, outBuffPosn); - return result; - } - - /** - * Encodes up to three bytes of the array <code>src</code> and writes the - * resulting four Base64 bytes to <code>dest</code>. The source and - * destination arrays can be manipulated anywhere along their length by - * specifying <code>sOffset</code> and <code>dOffset</code>. - * <p> - * This method does not check to make sure the arrays are large enough to - * accomodate <code>sOffset + 3</code> for the <code>src</code> array or - * <code>dOffset + 4</code> for the <code>dest</code> array. The actual - * number of significant bytes in the input array is given by - * <code>numBytes</code>. - * - * @param src the array to convert. - * @param sOffset the index where conversion begins. - * @param numBytes the number of significant bytes in your array. - * @param dest the array to hold the conversion. - * @param dOffset the index where output will be put. - * @return the <code>destination</code> array. - */ - private static final byte[] encode3to4(final byte[] src, final int sOffset, - final int numBytes, final byte[] dest, - final int dOffset) - { - // 1 2 3 - // 01234567890123456789012345678901 Bit position - // --------000000001111111122222222 Array position from threeBytes - // --------| || || || | Six bit groups to index ALPHABET - // >>18 >>12 >> 6 >> 0 Right shift necessary - // 0x3F 0x3F 0x3F Additional AND - - // Create buffer with zero-padding if there are only one or two - // significant bytes passed in the array. - // We have to shift left 24 in order to flush out the 1's that appear - // when Java treats a value as negative that is cast from a byte to an int. - final int inBuff = (numBytes > 0 ? ((src[sOffset] << 24) >>> 8) : 0) - | (numBytes > 1 ? ((src[sOffset + 1] << 24) >>> 16) : 0) - | (numBytes > 2 ? ((src[sOffset + 2] << 24) >>> 24) : 0); - switch (numBytes) - { - case 3: - dest[dOffset ] = ALPHABET[(inBuff >>> 18)]; - dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; - dest[dOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3F]; - dest[dOffset + 3] = ALPHABET[(inBuff) & 0x3F]; - break; - case 2: - dest[dOffset ] = ALPHABET[(inBuff >>> 18)]; - dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; - dest[dOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3F]; - dest[dOffset + 3] = EQUALS_SIGN; - break; - case 1: - dest[dOffset ] = ALPHABET[(inBuff >>> 18)]; - dest[dOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3F]; - dest[dOffset + 2] = EQUALS_SIGN; - dest[dOffset + 3] = EQUALS_SIGN; - break; - } - return dest; - } - - /** - * Decodes four bytes from array <code>src</code> and writes the resulting - * bytes (up to three of them) to <code>dest</code>. - * <p> - * The source and destination arrays can be manipulated anywhere along their - * length by specifying <code>sOffset</code> and <code>dOffset</code>. - * <p> - * This method does not check to make sure your arrays are large enough to - * accomodate <code>sOffset + 4</code> for the <code>src</code> array or - * <code>dOffset + 3</code> for the <code>dest</code> array. This method - * returns the actual number of bytes that were converted from the Base64 - * encoding. - * - * @param src the array to convert. - * @param sOffset the index where conversion begins. - * @param dest the array to hold the conversion. - * @param dOffset the index where output will be put. - * @return the number of decoded bytes converted. - */ - private static final int decode4to3(final byte[] src, final int sOffset, - final byte[] dest, final int dOffset) - { - if (src[sOffset + 2] == EQUALS_SIGN) // Example: Dk== - { - final int outBuff = ((DECODABET[src[sOffset ]] & 0xFF) << 18) - | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12); - dest[dOffset] = (byte)(outBuff >>> 16); - return 1; - } - if (src[sOffset + 3] == EQUALS_SIGN) // Example: DkL= - { - final int outBuff = ((DECODABET[src[sOffset ]] & 0xFF) << 18) - | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12) - | ((DECODABET[src[sOffset + 2]] & 0xFF) << 6); - dest[dOffset ] = (byte)(outBuff >>> 16); - dest[dOffset + 1] = (byte)(outBuff >>> 8); - return 2; - } - try // Example: DkLE - { - final int outBuff = ((DECODABET[src[sOffset ]] & 0xFF) << 18) - | ((DECODABET[src[sOffset + 1]] & 0xFF) << 12) - | ((DECODABET[src[sOffset + 2]] & 0xFF) << 6) - | ((DECODABET[src[sOffset + 3]] & 0xFF)); - dest[dOffset ] = (byte)(outBuff >> 16); - dest[dOffset + 1] = (byte)(outBuff >> 8); - dest[dOffset + 2] = (byte) outBuff; - return 3; - } - catch (Exception x) - { - if (Configuration.DEBUG) - { - log.fine("" + src[sOffset ] + ": " + (DECODABET[src[sOffset ]])); - log.fine("" + src[sOffset + 1] + ": " + (DECODABET[src[sOffset + 1]])); - log.fine("" + src[sOffset + 2] + ": " + (DECODABET[src[sOffset + 2]])); - log.fine("" + src[sOffset + 3] + ": " + (DECODABET[src[sOffset + 3]])); - } - return -1; - } - } -} diff --git a/libjava/classpath/gnu/java/security/x509/X509Certificate.java b/libjava/classpath/gnu/java/security/x509/X509Certificate.java index b3f8a696a85..14c5652648a 100644 --- a/libjava/classpath/gnu/java/security/x509/X509Certificate.java +++ b/libjava/classpath/gnu/java/security/x509/X509Certificate.java @@ -1,5 +1,5 @@ /* X509Certificate.java -- X.509 certificate. - Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -48,6 +48,7 @@ import gnu.java.security.der.DERValue; import gnu.java.security.x509.ext.BasicConstraints; import gnu.java.security.x509.ext.ExtendedKeyUsage; import gnu.java.security.x509.ext.Extension; +import gnu.java.security.x509.ext.GeneralName; import gnu.java.security.x509.ext.IssuerAlternativeNames; import gnu.java.security.x509.ext.KeyUsage; import gnu.java.security.x509.ext.SubjectAlternativeNames; @@ -103,6 +104,7 @@ public class X509Certificate extends java.security.cert.X509Certificate // Constants and fields. // ------------------------------------------------------------------------ + private static final long serialVersionUID = -2491127588187038216L; private static final Logger logger = SystemLogger.SYSTEM; protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1"); @@ -133,7 +135,7 @@ public class X509Certificate extends java.security.cert.X509Certificate protected transient PublicKey subjectKey; protected transient BitString issuerUniqueId; protected transient BitString subjectUniqueId; - protected transient Map extensions; + protected transient Map<OID, Extension> extensions; // Signature. protected transient OID sigAlgId; @@ -157,7 +159,7 @@ public class X509Certificate extends java.security.cert.X509Certificate throws CertificateException, IOException { super(); - extensions = new HashMap(); + extensions = new HashMap<OID, Extension>(); try { parse(encoded); @@ -178,7 +180,7 @@ public class X509Certificate extends java.security.cert.X509Certificate protected X509Certificate() { - extensions = new HashMap(); + extensions = new HashMap<OID, Extension>(); } // X509Certificate methods. @@ -316,17 +318,15 @@ public class X509Certificate extends java.security.cert.X509Certificate return null; } - public List getExtendedKeyUsage() throws CertificateParsingException + public List<String> getExtendedKeyUsage() throws CertificateParsingException { Extension e = getExtension(ExtendedKeyUsage.ID); if (e != null) { - List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds(); - List b = new ArrayList(a.size()); - for (Iterator it = a.iterator(); it.hasNext(); ) - { - b.add(it.next().toString()); - } + List<OID> a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds(); + List<String> b = new ArrayList<String>(a.size()); + for (OID oid : a) + b.add(oid.toString()); return Collections.unmodifiableList(b); } return null; @@ -342,24 +342,44 @@ public class X509Certificate extends java.security.cert.X509Certificate return -1; } - public Collection getSubjectAlternativeNames() + public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException { Extension e = getExtension(SubjectAlternativeNames.ID); if (e != null) { - return ((SubjectAlternativeNames) e.getValue()).getNames(); + List<GeneralName> names + = ((SubjectAlternativeNames) e.getValue()).getNames(); + List<List<?>> list = new ArrayList<List<?>>(names.size()); + for (GeneralName name : names) + { + List<Object> n = new ArrayList<Object>(2); + n.add(name.kind().tag()); + n.add(name.name()); + list.add(n); + } + return list; } return null; } - public Collection getIssuerAlternativeNames() + public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException { Extension e = getExtension(IssuerAlternativeNames.ID); if (e != null) { - return ((IssuerAlternativeNames) e.getValue()).getNames(); + List<GeneralName> names + = ((IssuerAlternativeNames) e.getValue()).getNames(); + List<List<?>> list = new ArrayList<List<?>>(names.size()); + for (GeneralName name : names) + { + List<Object> n = new ArrayList<Object>(2); + n.add(name.kind().tag()); + n.add(name.name()); + list.add(n); + } + return list; } return null; } @@ -378,24 +398,22 @@ public class X509Certificate extends java.security.cert.X509Certificate return false; } - public Set getCriticalExtensionOIDs() + public Set<String> getCriticalExtensionOIDs() { - HashSet s = new HashSet(); - for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + HashSet<String> s = new HashSet<String>(); + for (Extension e : extensions.values()) { - Extension e = (Extension) it.next(); if (e.isCritical()) s.add(e.getOid().toString()); } return Collections.unmodifiableSet(s); } - public Set getNonCriticalExtensionOIDs() + public Set<String> getNonCriticalExtensionOIDs() { - HashSet s = new HashSet(); - for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + HashSet<String> s = new HashSet<String>(); + for (Extension e : extensions.values()) { - Extension e = (Extension) it.next(); if (!e.isCritical()) s.add(e.getOid().toString()); } diff --git a/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java b/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java index 50bc6d367d7..c451762f8e0 100644 --- a/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java +++ b/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java @@ -1,5 +1,5 @@ /* CertificatePolicies.java -- certificate policy extension. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -61,8 +61,8 @@ public class CertificatePolicies extends Extension.Value public static final OID ID = new OID("2.5.29.32"); - private final List policies; - private final Map policyQualifierInfos; + private final List<OID> policies; + private final Map<OID, List<PolicyQualifierInfo>> policyQualifierInfos; // Constructor. // ------------------------------------------------------------------------- @@ -76,8 +76,9 @@ public class CertificatePolicies extends Extension.Value throw new IOException("malformed CertificatePolicies"); int len = 0; - LinkedList policyList = new LinkedList(); - HashMap qualifierMap = new HashMap(); + LinkedList<OID> policyList = new LinkedList<OID>(); + HashMap<OID, List<PolicyQualifierInfo>> qualifierMap + = new HashMap<OID, List<PolicyQualifierInfo>>(); while (len < pol.getLength()) { DERValue policyInfo = der.read(); @@ -92,7 +93,7 @@ public class CertificatePolicies extends Extension.Value { DERValue qual = der.read(); int len2 = 0; - LinkedList quals = new LinkedList(); + LinkedList<PolicyQualifierInfo> quals = new LinkedList<PolicyQualifierInfo>(); while (len2 < qual.getLength()) { val = der.read(); @@ -109,8 +110,8 @@ public class CertificatePolicies extends Extension.Value policyQualifierInfos = Collections.unmodifiableMap(qualifierMap); } - public CertificatePolicies (final List policies, - final Map policyQualifierInfos) + public CertificatePolicies (final List<OID> policies, + final Map<OID, List<PolicyQualifierInfo>> policyQualifierInfos) { for (Iterator it = policies.iterator(); it.hasNext(); ) if (!(it.next() instanceof OID)) @@ -129,54 +130,69 @@ public class CertificatePolicies extends Extension.Value throw new IllegalArgumentException ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); } - this.policies = Collections.unmodifiableList (new ArrayList (policies)); + this.policies = Collections.unmodifiableList (new ArrayList<OID>(policies)); this.policyQualifierInfos = Collections.unmodifiableMap - (new HashMap (policyQualifierInfos)); + (new HashMap<OID, List<PolicyQualifierInfo>>(policyQualifierInfos)); } // Instance methods. // ------------------------------------------------------------------------- - public List getPolicies() + public List<OID> getPolicies() { return policies; } + + /** + * Returns the list of policy OIDs, formatted as dotted-decimal strings. + * + * @return + */ + public List<String> getPolicyStrings() + { + List<String> l = new ArrayList<String>(policies.size()); + for (OID oid : policies) + { + l.add(oid.toString()); + } + return l; + } - public List getPolicyQualifierInfos(OID oid) + public List<PolicyQualifierInfo> getPolicyQualifierInfos(OID oid) { - return (List) policyQualifierInfos.get(oid); + return policyQualifierInfos.get(oid); } public byte[] getEncoded() { if (encoded == null) { - List pol = new ArrayList (policies.size()); - for (Iterator it = policies.iterator(); it.hasNext(); ) + List<DERValue> pol = new ArrayList<DERValue>(policies.size()); + for (Iterator<OID> it = policies.iterator(); it.hasNext(); ) { - OID policy = (OID) it.next(); - List qualifiers = getPolicyQualifierInfos (policy); - List l = new ArrayList (qualifiers == null ? 1 : 2); - l.add (new DERValue (DER.OBJECT_IDENTIFIER, policy)); + OID policy = it.next(); + List<PolicyQualifierInfo> qualifiers = getPolicyQualifierInfos(policy); + List<DERValue> l = new ArrayList<DERValue>(qualifiers == null ? 1 : 2); + l.add(new DERValue(DER.OBJECT_IDENTIFIER, policy)); if (qualifiers != null) { - List ll = new ArrayList (qualifiers.size()); - for (Iterator it2 = qualifiers.iterator(); it.hasNext(); ) + List<DERValue> ll = new ArrayList<DERValue>(qualifiers.size()); + for (Iterator<PolicyQualifierInfo> it2 = qualifiers.iterator(); it.hasNext(); ) { - PolicyQualifierInfo info = (PolicyQualifierInfo) it2.next(); + PolicyQualifierInfo info = it2.next(); try { - ll.add (DERReader.read (info.getEncoded())); + ll.add(DERReader.read(info.getEncoded())); } catch (IOException ioe) { } } - l.add (new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, ll)); + l.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, ll)); } - pol.add (new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, l)); + pol.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, l)); } - encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, pol).getEncoded(); + encoded = new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, pol).getEncoded(); } return (byte[]) encoded.clone(); } diff --git a/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java b/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java index 37b08acf43e..428013d04bd 100644 --- a/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java +++ b/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java @@ -1,5 +1,5 @@ /* ExtendedKeyUsage.java -- the extended key usage extension. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -56,7 +56,7 @@ public class ExtendedKeyUsage extends Extension.Value public static final OID ID = new OID("2.5.29.37"); - private final List purposeIds; + private final List<OID> purposeIds; // Constructor. // ------------------------------------------------------------------------- @@ -69,13 +69,13 @@ public class ExtendedKeyUsage extends Extension.Value if (!usageList.isConstructed()) throw new IOException("malformed ExtKeyUsageSyntax"); int len = 0; - purposeIds = new LinkedList(); + purposeIds = new LinkedList<OID>(); while (len < usageList.getLength()) { DERValue val = der.read(); if (val.getTag() != DER.OBJECT_IDENTIFIER) throw new IOException("malformed KeyPurposeId"); - purposeIds.add(val.getValue()); + purposeIds.add((OID) val.getValue()); len += val.getEncodedLength(); } } @@ -83,7 +83,7 @@ public class ExtendedKeyUsage extends Extension.Value // Instance method. // ------------------------------------------------------------------------- - public List getPurposeIds() + public List<OID> getPurposeIds() { return Collections.unmodifiableList(purposeIds); } diff --git a/libjava/classpath/gnu/java/security/x509/ext/Extension.java b/libjava/classpath/gnu/java/security/x509/ext/Extension.java index 69251987ec9..2b7e96d5abc 100644 --- a/libjava/classpath/gnu/java/security/x509/ext/Extension.java +++ b/libjava/classpath/gnu/java/security/x509/ext/Extension.java @@ -1,5 +1,5 @@ /* Extension.java -- an X.509 certificate or CRL extension. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -171,6 +171,10 @@ public class Extension { value = new ReasonCode(encval); } + else if (oid.equals(NameConstraints.ID)) + { + value = new NameConstraints(encval); + } else { value = new Value(encval); @@ -226,11 +230,11 @@ public class Extension public DERValue getDerValue() { - List ext = new ArrayList (3); - ext.add (new DERValue (DER.OBJECT_IDENTIFIER, oid)); - ext.add (new DERValue (DER.BOOLEAN, Boolean.valueOf (critical))); - ext.add (new DERValue (DER.OCTET_STRING, value.getEncoded())); - return new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, ext); + List<DERValue> ext = new ArrayList<DERValue>(3); + ext.add(new DERValue(DER.OBJECT_IDENTIFIER, oid)); + ext.add(new DERValue(DER.BOOLEAN, Boolean.valueOf(critical))); + ext.add(new DERValue(DER.OCTET_STRING, value.getEncoded())); + return new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, ext); } // Own methods. diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralName.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralName.java new file mode 100644 index 00000000000..fbc05339f6d --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralName.java @@ -0,0 +1,232 @@ +/* GeneralName.java -- a GeneralName. + 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.security.x509.ext; + +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; +import java.util.Arrays; + +/** + * The GeneralName structure from X.509. + * + * <pre> + GeneralName ::= CHOICE { + otherName [0] OtherName, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } + + OtherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER, + value [0] EXPLICIT ANY DEFINED BY type-id } + + EDIPartyName ::= SEQUENCE { + nameAssigner [0] DirectoryString OPTIONAL, + partyName [1] DirectoryString } +</pre> + * + * @author Casey Marshall (csm@gnu.org) + */ +public class GeneralName +{ + public static enum Kind + { + otherName (0), + rfc822Name (1), + dNSName (2), + x400Address (3), + directoryName (4), + ediPartyName (5), + uniformResourceIdentifier (6), + iPAddress (7), + registeredId (8); + + private int tag; + + private Kind(int tag) + { + this.tag = tag; + } + + public static Kind forTag(final int tag) + { + switch (tag) + { + case 0: return otherName; + case 1: return rfc822Name; + case 2: return dNSName; + case 3: return x400Address; + case 4: return directoryName; + case 5: return ediPartyName; + case 6: return uniformResourceIdentifier; + case 7: return iPAddress; + case 8: return registeredId; + } + + throw new IllegalArgumentException("invalid tag: " + tag); + } + + public int tag() + { + return tag; + } + }; + + private final Kind kind; + private final byte[] name; + private final byte[] encoded; + + public GeneralName(byte[] encoded) throws IOException + { + DERReader reader = new DERReader(encoded); + DERValue value = reader.read(); + + if (value.getTagClass() != DER.CONTEXT) + throw new IOException("malformed GeneralName"); + + this.encoded = value.getEncoded(); + + kind = Kind.forTag(value.getTag()); + switch (kind) + { + case otherName: + name = value.getEncoded(); + name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE); + // Skip the two fields of the name. + reader.read(); // OID + reader.read(); // Octet string + break; + + case rfc822Name: + name = (byte[]) value.getValue(); + break; + + case dNSName: + name = (byte[]) value.getValue(); + break; + + case x400Address: + name = (byte[]) value.getValue(); + break; + + case directoryName: + name = value.getEncoded(); + name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE); + break; + + case ediPartyName: + name = value.getEncoded(); + name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE); + break; + + case uniformResourceIdentifier: + name = (byte[]) value.getValue(); + break; + + case iPAddress: + name = (byte[]) value.getValue(); + break; + + case registeredId: + name = value.getEncoded(); + name[0] = DER.OBJECT_IDENTIFIER; + break; + + default: + name = null; // Not reached. + } + } + + public GeneralName(Kind kind, byte[] name) + { + this.kind = kind; + this.name = (byte[]) name.clone(); + this.encoded = null; + } + + public Kind kind() + { + return kind; + } + + public byte[] name() + { + return (byte[]) name.clone(); + } + + public byte[] encoded() + { + try + { + return (byte[]) encoded.clone(); + } + catch (NullPointerException npe) + { + return null; + } + } + + public boolean equals(Object o) + { + try + { + GeneralName that = (GeneralName) o; + return (that.kind() == kind() && Arrays.equals(name, that.name)); + } + catch (ClassCastException cce) + { + return false; + } + } + + public String toString() + { + return (super.toString() + " [ kind=" + kind + "; name=" + + Util.hexDump(name, "") + " ]"); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java index b342cbd5f2e..f56ee963b9c 100644 --- a/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java @@ -38,106 +38,38 @@ exception statement from your version. */ package gnu.java.security.x509.ext; -import gnu.java.security.OID; -import gnu.java.security.der.DER; import gnu.java.security.der.DERReader; import gnu.java.security.der.DERValue; import java.io.IOException; -import java.net.InetAddress; -import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import javax.security.auth.x500.X500Principal; - public class GeneralNames { // Instance methods. // ------------------------------------------------------------------------- - public static final int OTHER_NAME = 0; - public static final int RFC822_NAME = 1; - public static final int DNS_NAME = 2; - public static final int X400_ADDRESS = 3; - public static final int DIRECTORY_NAME = 4; - public static final int EDI_PARTY_NAME = 5; - public static final int URI = 6; - public static final int IP_ADDRESS = 7; - public static final int REGISTERED_ID = 8; - - private List names; + private List<GeneralName> names; // Constructor. // ------------------------------------------------------------------------- public GeneralNames(final byte[] encoded) throws IOException { - names = new LinkedList(); + names = new LinkedList<GeneralName>(); DERReader der = new DERReader(encoded); DERValue nameList = der.read(); if (!nameList.isConstructed()) throw new IOException("malformed GeneralNames"); int len = 0; - int i = 0; while (len < nameList.getLength()) { DERValue name = der.read(); - List namePair = new ArrayList(2); - int tagClass = name.getTagClass(); - if (tagClass != DER.CONTEXT) - throw new IOException("malformed GeneralName: Tag class is " + tagClass); - namePair.add(Integer.valueOf(name.getTag())); - DERValue val = null; - switch (name.getTag()) - { - case RFC822_NAME: - case DNS_NAME: - case X400_ADDRESS: - case URI: - namePair.add(new String((byte[]) name.getValue())); - break; - - case OTHER_NAME: - // MUST return the encoded bytes of the OID/OctetString sequence - byte[] anotherName = name.getEncoded(); - anotherName[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); - namePair.add(anotherName); - // DERReader goes back on Constructed things so we need to skip over them - DERValue skip = der.read(); // skip OID - skip = der.read(); // skip Octet String - break; - - case EDI_PARTY_NAME: - namePair.add(name.getValue()); - break; - - case DIRECTORY_NAME: - byte[] b = name.getEncoded(); - b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); - DERReader r = new DERReader (b); - r.read (); - namePair.add(new X500Principal(r.read ().getEncoded ()).toString()); - break; - - case IP_ADDRESS: - namePair.add(InetAddress.getByAddress((byte[]) name.getValue()) - .getHostAddress()); - break; - - case REGISTERED_ID: - byte[] bb = name.getEncoded(); - bb[0] = (byte) DER.OBJECT_IDENTIFIER; - namePair.add(new OID(bb).toString()); - break; - - default: - throw new IOException("unknown tag " + name.getTag()); - } - names.add(namePair); + GeneralName generalName = new GeneralName(name.getEncoded()); + names.add(generalName); len += name.getEncodedLength(); } } @@ -145,21 +77,9 @@ public class GeneralNames // Instance methods. // ------------------------------------------------------------------------- - public List getNames() + public List<GeneralName> getNames() { - List l = new ArrayList(names.size()); - for (Iterator it = names.iterator(); it.hasNext(); ) - { - List ll = (List) it.next(); - List pair = new ArrayList(2); - pair.add(ll.get(0)); - if (ll.get(1) instanceof byte[]) - pair.add(((byte[]) ll.get(1)).clone()); - else - pair.add(ll.get(1)); - l.add(Collections.unmodifiableList(pair)); - } - return Collections.unmodifiableList(l); + return Collections.unmodifiableList(names); } public String toString() diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java new file mode 100644 index 00000000000..5f6ffd98701 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java @@ -0,0 +1,156 @@ +/* GeneralSubtree.java -- + 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.security.x509.ext; + +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * The GeneralSubtree structure, a part of the {@link NameConstraints} + * extension. + * + * <pre> + GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] BaseDistance DEFAULT 0, + maximum [1] BaseDistance OPTIONAL } + + BaseDistance ::= INTEGER (0..MAX)</pre> + * + * @author Casey Marshall (csm@gnu.org) + */ +public class GeneralSubtree +{ + private final GeneralName base; + private final int minimum; + private final int maximum; + + public GeneralSubtree(byte[] encoded) throws IOException + { + DERReader reader = new DERReader(encoded); + DERValue generalSubtree = reader.read(); + + if (!generalSubtree.isConstructed()) + throw new IOException("malformed GeneralSubtree"); + + DERValue generalName = reader.read(); + base = new GeneralName(generalName.getEncoded()); + if (generalName.isConstructed()) + reader.skip(generalName.getLength()); + + int len = generalName.getEncodedLength(); + if (len < generalSubtree.getLength()) + { + DERValue distance = reader.read(); + if (distance.getTag() == 0) + { + minimum = ((BigInteger) distance.getValue()).intValue(); + len += distance.getEncodedLength(); + if (len < generalSubtree.getLength()) + { + distance = reader.read(); + if (distance.getTag() != 1) + throw new IOException("unexpected tag " + + distance.getTag() + + " (expected 1 for GeneralSubtree maximum distance)"); + maximum = ((BigInteger) distance.getValue()).intValue(); + } + else + { + maximum = -1; + } + } + else if (distance.getTag() == 1) + { + minimum = 1; + maximum = ((BigInteger) distance.getValue()).intValue(); + } + else + { + throw new IOException("unexpected tag " + distance.getTag() + + " (expected 0 or 1 for GeneralSubtree distance)"); + } + } + else + { + minimum = 0; + maximum = -1; + } + } + + /** + * Returns the base name. + * + * @return The base name. + */ + public GeneralName base() + { + return base; + } + + /** + * Returns the minimum base distance, possibly zero. + * + * @return The minimum base distance. + */ + public int minimum() + { + return minimum; + } + + /** + * Returns the maximum base distance, or -1 if this value was not specified. + * + * @return The maximum base distance. + */ + public int maximum() + { + return maximum; + } + + public String toString() + { + return (GeneralSubtree.class.getName() + " [ base=" + base + + "; minimum=" + minimum + "; maximim=" + maximum + + " ]"); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java b/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java index 8b017dc62d8..080070b9890 100644 --- a/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java +++ b/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java @@ -1,5 +1,5 @@ /* IssuerAlternatuveNames.java -- issuer alternative names extension. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -65,7 +65,7 @@ public class IssuerAlternativeNames extends Extension.Value // Instance method. // ------------------------------------------------------------------------- - public List getNames() + public List<GeneralName> getNames() { return names.getNames(); } diff --git a/libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java b/libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java new file mode 100644 index 00000000000..607c4296642 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java @@ -0,0 +1,161 @@ +/* NameConstraints.java -- the NameConstraints X.509 extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.Extension.Value; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * The NameConstraints extension. From RFC 3280, section 4.2.1.11, this + * extension is defined as: + * + * <pre> + id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } + + NameConstraints ::= SEQUENCE { + permittedSubtrees [0] GeneralSubtrees OPTIONAL, + excludedSubtrees [1] GeneralSubtrees OPTIONAL } + + GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + + GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] BaseDistance DEFAULT 0, + maximum [1] BaseDistance OPTIONAL } + + BaseDistance ::= INTEGER (0..MAX) + </pre> + * + * See also the classes {@link GeneralNames} and {@link GeneralSubtree}. + * + * @author csm + */ +public class NameConstraints extends Value +{ + public static final OID ID = new OID("2.5.29.30"); + + private List<GeneralSubtree> permittedSubtrees; + private List<GeneralSubtree> excludedSubtrees; + + public NameConstraints(byte[] encoded) throws IOException + { + super(encoded); + + DERReader der = new DERReader(encoded); + DERValue value = der.read(); + if (!value.isConstructed()) + { + throw new IOException("malformed NameConstraints"); + } + + permittedSubtrees = new LinkedList<GeneralSubtree>(); + excludedSubtrees = new LinkedList<GeneralSubtree>(); + int len = 0; + if (len < value.getLength()) + { + DERValue subtrees = der.read(); + if (subtrees.getTag() == 0) + { + int len2 = 0; + while (len2 < subtrees.getLength()) + { + DERValue subtree = der.read(); + permittedSubtrees.add(new GeneralSubtree(subtree.getEncoded())); + der.skip(subtree.getLength()); + len2 += subtree.getEncodedLength(); + } + len += subtrees.getEncodedLength(); + + if (len < value.getLength()) + { + subtrees = der.read(); + if (subtrees.getTag() != 1) + throw new IOException("unexpected tag " + subtrees.getTag() + + " (expecting 1 for excludedSubtrees)"); + len2 = 0; + while (len2 < subtrees.getLength()) + { + DERValue subtree = der.read(); + excludedSubtrees.add(new GeneralSubtree(subtree.getEncoded())); + der.skip(subtree.getLength()); + len2 += subtree.getEncodedLength(); + } + } + } + else if (subtrees.getTag() == 1) + { + int len2 = 0; + while (len2 < subtrees.getLength()) + { + DERValue subtree = der.read(); + excludedSubtrees.add(new GeneralSubtree(subtree.getEncoded())); + der.skip(subtree.getLength()); + len2 += subtree.getEncodedLength(); + } + } + else + throw new IOException("unexpected tag " + subtrees.getTag() + + " (expecting 0 or 1)"); + } + } + + public List<GeneralSubtree> permittedSubtrees() + { + return Collections.unmodifiableList(permittedSubtrees); + } + + public List<GeneralSubtree> excludedSubtrees() + { + return Collections.unmodifiableList(excludedSubtrees); + } + + public String toString() + { + return NameConstraints.class.getName() + " [ permittedSubtrees=" + + permittedSubtrees + "; excludedSubtrees=" + excludedSubtrees + + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java b/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java index f88e854965f..8b6347d99a3 100644 --- a/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java +++ b/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java @@ -1,5 +1,5 @@ /* SubjectAlternatuveNames.java -- subject alternative names extension. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -65,7 +65,7 @@ public class SubjectAlternativeNames extends Extension.Value // Instance method. // ------------------------------------------------------------------------- - public List getNames() + public List<GeneralName> getNames() { return names.getNames(); } diff --git a/libjava/classpath/gnu/java/util/Base64.java b/libjava/classpath/gnu/java/util/Base64.java new file mode 100644 index 00000000000..592696bcc80 --- /dev/null +++ b/libjava/classpath/gnu/java/util/Base64.java @@ -0,0 +1,340 @@ +/* Base64.java -- Base64 encoding and decoding. + Copyright (C) 2006, 2007 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. + +-- +Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP +follow. See http://www.isc.org/products/DHCP/. + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-- +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute +this Software with or without fee, provided that the above copyright +notice and all paragraphs of this notice appear in all copies, and +that the name of IBM not be used in connection with the marketing of +any product incorporating the Software or modifications thereof, +without specific, written prior permission. + +To the extent it has a right to do so, IBM grants an immunity from +suit under its patents, if any, for the use, sale or manufacture of +products to the extent that such products are used for performing +Domain Name System dynamic updates in TCP/IP networks by means of the +Software. No immunity is granted for any product per se or for any +other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH +DAMAGES. */ + + +package gnu.java.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public final class Base64 +{ + + // No constructor. + private Base64() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** Base-64 characters. */ + private static final String BASE_64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** Base-64 padding character. */ + private static final char BASE_64_PAD = '='; + + /** + * Base64 encode a byte array, with no line wrapping. + * + * @param buf The byte array to encode. + * @return <tt>buf</tt> encoded in Base64. + */ + public static String encode(byte[] buf) + { + return encode(buf, 0); + } + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return <tt>buf</tt> encoded in Base64. + */ + public static String encode(byte[] buf, int tw) + { + return encode(buf, 0, buf.length, tw); + } + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param offset The offset in the byte array to start. + * @param length The number of bytes to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return <tt>buf</tt> encoded in Base64. + */ + public static String encode(byte[] buf, int offset, int length, int tw) + { + if (offset < 0 || length < 0 || offset + length > buf.length) + throw new ArrayIndexOutOfBoundsException(buf.length + " " + + offset + " " + + length); + int srcLength = buf.length - offset; + byte[] input = new byte[3]; + int[] output = new int[4]; + StringBuffer out = new StringBuffer(); + int i = offset; + int chars = 0; + + while (srcLength > 2) + { + input[0] = buf[i++]; + input[1] = buf[i++]; + input[2] = buf[i++]; + srcLength -= 3; + + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + output[3] = input[2] & 0x3f; + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[2])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[3])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + + if (srcLength != 0) + { + input[0] = input[1] = input[2] = 0; + for (int j = 0; j < srcLength; j++) + { + input[j] = buf[i+j]; + } + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + if (srcLength == 1) + { + out.append(BASE_64_PAD); + } + else + { + out.append(BASE_64.charAt(output[2])); + } + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64_PAD); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + if (tw > 0) + { + out.append("\n"); + } + + return out.toString(); + } + + /** + * Decode a Base-64 string into a byte array. + * + * @param b64 The Base-64 encoded string. + * @return The decoded bytes. + * @throws java.io.IOException If the argument is not a valid Base-64 + * encoding. + */ + public static byte[] decode(String b64) throws IOException + { + ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); + int state = 0, i; + byte temp = 0; + + for (i = 0; i < b64.length(); i++) + { + if (Character.isWhitespace(b64.charAt(i))) + { + continue; + } + if (b64.charAt(i) == BASE_64_PAD) + { + break; + } + + int pos = BASE_64.indexOf(b64.charAt(i)); + if (pos < 0) + { + throw new IOException("non-Base64 character " + b64.charAt(i)); + } + switch (state) + { + case 0: + temp = (byte) (pos - BASE_64.indexOf('A') << 2); + state = 1; + break; + + case 1: + temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); + state = 2; + break; + + case 2: + temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); + state = 3; + break; + + case 3: + temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); + result.write(temp); + state = 0; + break; + + default: + throw new Error("this statement should be unreachable"); + } + } + + if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) + { + switch (state) + { + case 0: + case 1: + throw new IOException("malformed Base64 sequence"); + + case 2: + i++; + for ( ; i < b64.length(); i++) + { + if (!Character.isWhitespace(b64.charAt(i))) + { + break; + } + } + // We must see a second pad character here. + if (b64.charAt(i) != BASE_64_PAD) + { + throw new IOException("malformed Base64 sequence"); + } + i++; + // Fall-through. + + case 3: + i++; + for ( ; i < b64.length(); i++) + { + // We should only see whitespace after this. + if (!Character.isWhitespace(b64.charAt(i))) + { + throw new IOException("malformed Base64 sequence"); + } + } + } + } + else + { + if (state != 0) + { + throw new IOException("malformed Base64 sequence"); + } + } + + return result.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/EventDispatcher.java b/libjava/classpath/gnu/java/util/prefs/EventDispatcher.java index ecddd3a55f2..f73c3e70311 100644 --- a/libjava/classpath/gnu/java/util/prefs/EventDispatcher.java +++ b/libjava/classpath/gnu/java/util/prefs/EventDispatcher.java @@ -53,7 +53,7 @@ public class EventDispatcher extends Thread // This is a queue of events to dispatch. This thread waits on // the queue and when notified will remove events until the queue // is empty. - private static final ArrayList queue = new ArrayList(); + private static final ArrayList<Runnable> queue = new ArrayList<Runnable>(); // FIXME: this thread probably ought to go in some classpath-internal // ThreadGroup. But we don't have that yet. @@ -81,7 +81,7 @@ public class EventDispatcher extends Thread // Ignore. } } - r = (Runnable) queue.remove(0); + r = queue.remove(0); } // Invoke outside the synchronization, so that // we aren't blocking other threads from posting events. diff --git a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java index a7e2322b524..0fd4df36616 100644 --- a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java +++ b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java @@ -41,7 +41,6 @@ import gnu.java.util.prefs.gconf.GConfNativePeer; import java.security.Permission; -import java.util.Iterator; import java.util.List; import java.util.prefs.AbstractPreferences; import java.util.prefs.BackingStoreException; @@ -185,7 +184,7 @@ public class GConfBasedPreferences */ protected String[] childrenNamesSpi() throws BackingStoreException { - List nodeList = backend.getChildrenNodes(this.node); + List<String> nodeList = backend.getChildrenNodes(this.node); String[] nodes = new String[nodeList.size()]; nodeList.toArray(nodes); @@ -228,7 +227,7 @@ public class GConfBasedPreferences */ protected String[] keysSpi() throws BackingStoreException { - List keyList = backend.getKeys(this.node); + List<String> keyList = backend.getKeys(this.node); String[] keys = new String[keyList.size()]; keyList.toArray(keys); @@ -246,31 +245,24 @@ public class GConfBasedPreferences try { // gets the listing of directories in this node - List dirs = backend.getChildrenNodes(directory); + List<String> dirs = backend.getChildrenNodes(directory); if (dirs.size() != 0) { - String currentDir = null; - - for (Iterator itr = dirs.iterator(); itr.hasNext();) + for (String currentDir : dirs) { - currentDir = (String) itr.next(); - // recursive search inside this directory postorderRemove(currentDir); } } // remove all the keys associated to this directory - List entries = backend.getKeys(directory); + List<String> entries = backend.getKeys(directory); if (entries.size() != 0) { - String key = null; - - for (Iterator keys = entries.iterator(); keys.hasNext();) + for (String key : entries) { - key = (String) keys.next(); this.removeSpi(key); } } diff --git a/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java index cccb9bf2fc2..dc82379160b 100644 --- a/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java +++ b/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java @@ -52,7 +52,7 @@ public class MemoryBasedPreferences extends AbstractPreferences { private final boolean isUser; /** Contains all the preference entries of this node. */ - private HashMap entries = new HashMap(); + private HashMap<String, String> entries = new HashMap<String, String>(); /** * Creates a new preferences node with the given name and parent. @@ -98,7 +98,7 @@ public class MemoryBasedPreferences extends AbstractPreferences { * this node. */ protected String[] keysSpi() throws BackingStoreException { - return (String[]) entries.keySet().toArray(new String[entries.size()]); + return entries.keySet().toArray(new String[entries.size()]); } /** @@ -106,7 +106,7 @@ public class MemoryBasedPreferences extends AbstractPreferences { * null when the key has not been set. */ protected String getSpi(String key) { - return (String) entries.get(key); + return entries.get(key); } /** diff --git a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java index 6049863e916..5e12c718b2c 100644 --- a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java +++ b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java @@ -147,7 +147,7 @@ public final class GConfNativePeer * @return a java.util.List of keys. If there are no keys in the given node, a * list of size 0 is returned. */ - public List getKeys(String node) throws BackingStoreException + public List<String> getKeys(String node) throws BackingStoreException { return gconf_client_all_keys(node); } @@ -159,7 +159,7 @@ public final class GConfNativePeer * @param node the node to get subnodes from. If there are no subnodes in the * given node, a list of size 0 is returned. */ - public List getChildrenNodes(String node) throws BackingStoreException + public List<String> getChildrenNodes(String node) throws BackingStoreException { return gconf_client_all_nodes(node); } @@ -295,7 +295,7 @@ public final class GConfNativePeer * @return A list of nodes under the given source node. */ native - static final protected List gconf_client_all_nodes(String node) + static final protected List<String> gconf_client_all_nodes(String node) throws BackingStoreException; /** @@ -305,7 +305,7 @@ public final class GConfNativePeer * @return A list of all keys stored in the given node. */ native - static final protected List gconf_client_all_keys(String node) + static final protected List<String> gconf_client_all_keys(String node) throws BackingStoreException; /** diff --git a/libjava/classpath/gnu/java/util/regex/RETokenChar.java b/libjava/classpath/gnu/java/util/regex/RETokenChar.java index b70e6b1d843..42dcd93268a 100644 --- a/libjava/classpath/gnu/java/util/regex/RETokenChar.java +++ b/libjava/classpath/gnu/java/util/regex/RETokenChar.java @@ -113,7 +113,6 @@ final class RETokenChar extends REToken { boolean chain(REToken next) { if (next instanceof RETokenChar && ((RETokenChar)next).insens == insens) { RETokenChar cnext = (RETokenChar) next; - // assume for now that next can only be one character int newsize = ch.length + cnext.ch.length; char[] chTemp = new char [newsize]; @@ -122,7 +121,9 @@ final class RETokenChar extends REToken { System.arraycopy(cnext.ch,0,chTemp,ch.length,cnext.ch.length); ch = chTemp; - return false; + if (cnext.next == null) + return false; + return chain(cnext.next); } else return super.chain(next); } |