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
This commit is contained in:
Matthias Klose 2007-06-03 23:18:43 +00:00
parent af333b9a7f
commit e1bea0c068
2951 changed files with 80982 additions and 68583 deletions

View file

@ -172,7 +172,6 @@ public class gnuDynValue extends RecordAny implements DynValue,
else
return super.current_member_kind();
}
;
/** @inheritDoc */
public String current_member_name() throws TypeMismatch, InvalidValue
@ -182,7 +181,6 @@ public class gnuDynValue extends RecordAny implements DynValue,
else
return super.current_member_name();
}
;
/** @inheritDoc */
public NameDynAnyPair[] get_members_as_dyn_any() throws InvalidValue
@ -191,7 +189,6 @@ public class gnuDynValue extends RecordAny implements DynValue,
throw new InvalidValue(ISNULL);
return super.gnu_get_members_as_dyn_any();
}
;
/** @inheritDoc */
public NameValuePair[] get_members() throws InvalidValue
@ -201,7 +198,6 @@ public class gnuDynValue extends RecordAny implements DynValue,
else
return super.gnu_get_members();
}
;
/** @inheritDoc */
public void set_members_as_dyn_any(NameDynAnyPair[] value)
@ -210,7 +206,6 @@ public class gnuDynValue extends RecordAny implements DynValue,
super.set_members_as_dyn_any(value);
isNull = false;
}
;
/** @inheritDoc */
public void set_members(NameValuePair[] value)
@ -219,7 +214,6 @@ public class gnuDynValue extends RecordAny implements DynValue,
super.set_members(value);
isNull = false;
}
;
/** @inheritDoc */
public boolean is_null()

View file

@ -1348,7 +1348,6 @@ public class gnuPOA
{
return name;
}
;
/**
* Return the parent of this POA.

View file

@ -0,0 +1,126 @@
/* Pair.java -- A heterogenous pair of objects.
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.classpath;
/**
* A container for a pair of heterogenous objects.
*
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
*/
public class Pair<A,B>
{
/**
* The left-hand side of the pair.
*/
private A left;
/**
* The right-hand side of the pair.
*/
private B right;
/**
* Constructs a new pair using the given left and
* right values.
*
* @param left the left-hand side of the pair.
* @param right the right-hand side of the pair.
*/
public Pair(A left, B right)
{
this.left = left;
this.right = right;
}
/**
* Returns the left-hand side of the pair.
*
* @return the left-hand value.
*/
public A getLeft()
{
return left;
}
/**
* Returns the right-hand side of the pair.
*
* @return the right-hand value.
*/
public B getRight()
{
return right;
}
/**
* Returns true if the specified object is also a
* pair with equivalent left and right values.
*
* @param obj the object to compare.
* @return true if the two are equal.
*/
public boolean equals(Object obj)
{
if (obj instanceof Pair)
{
Pair<A,B> p = (Pair<A,B>) obj;
A lp = p.getLeft();
B rp = p.getRight();
return (lp == null ? left == null : lp.equals(left)) &&
(rp == null ? right == null : rp.equals(right));
}
return false;
}
/**
* Returns a hashcode for the pair, created by the
* summation of the hashcodes of the left and right
* hand values.
*
* @return a hashcode for the pair.
*/
public int hashCode()
{
return (left == null ? 0 : left.hashCode())
+ (right == null ? 0 : right.hashCode());
}
}

View file

@ -49,6 +49,7 @@ import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.ServiceConfigurationError;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
@ -176,7 +177,6 @@ public final class ServiceFactory
*/
private static final Logger LOGGER = Logger.getLogger("gnu.classpath");
/**
* Declared private in order to prevent constructing instances of
* this utility class.
@ -224,6 +224,51 @@ public final class ServiceFactory
*/
public static Iterator lookupProviders(Class spi,
ClassLoader loader)
{
return lookupProviders(spi, loader, false);
}
/**
* Finds service providers that are implementing the specified
* Service Provider Interface.
*
* <p><b>On-demand loading:</b> Loading and initializing service
* providers is delayed as much as possible. The rationale is that
* typical clients will iterate through the set of installed service
* providers until one is found that matches some criteria (like
* supported formats, or quality of service). In such scenarios, it
* might make sense to install only the frequently needed service
* providers on the local machine. More exotic providers can be put
* onto a server; the server will only be contacted when no suitable
* service could be found locally.
*
* <p><b>Security considerations:</b> Any loaded service providers
* are loaded through the specified ClassLoader, or the system
* ClassLoader if <code>classLoader</code> is
* <code>null</code>. When <code>lookupProviders</code> is called,
* the current {@link AccessControlContext} gets recorded. This
* captured security context will determine the permissions when
* services get loaded via the <code>next()</code> method of the
* returned <code>Iterator</code>.
*
* @param spi the service provider interface which must be
* implemented by any loaded service providers.
*
* @param loader the class loader that will be used to load the
* service providers, or <code>null</code> for the system class
* loader. For using the context class loader, see {@link
* #lookupProviders(Class)}.
* @param error true if a {@link ServiceConfigurationError}
* should be thrown when an error occurs, rather
* than it merely being logged.
* @return an iterator over instances of <code>spi</code>.
*
* @throws IllegalArgumentException if <code>spi</code> is
* <code>null</code>.
*/
public static Iterator lookupProviders(Class spi,
ClassLoader loader,
boolean error)
{
String resourceName;
Enumeration urls;
@ -246,10 +291,14 @@ public final class ServiceFactory
* does not return anything (no providers installed).
*/
log(Level.WARNING, "cannot access {0}", resourceName, ioex);
return Collections.EMPTY_LIST.iterator();
if (error)
throw new ServiceConfigurationError("Failed to access + " +
resourceName, ioex);
else
return Collections.EMPTY_LIST.iterator();
}
return new ServiceIterator(spi, urls, loader,
return new ServiceIterator(spi, urls, loader, error,
AccessController.getContext());
}
@ -342,6 +391,11 @@ public final class ServiceFactory
*/
private Object nextProvider;
/**
* True if a {@link ServiceConfigurationError} should be thrown
* when an error occurs, instead of it merely being logged.
*/
private boolean error;
/**
* Constructs an Iterator that loads and initializes services on
@ -359,16 +413,21 @@ public final class ServiceFactory
* @param loader the ClassLoader that gets used for loading
* service providers.
*
* @param error true if a {@link ServiceConfigurationError}
* should be thrown when an error occurs, rather
* than it merely being logged.
*
* @param securityContext the security context to use when loading
* and initializing service providers.
*/
ServiceIterator(Class spi, Enumeration urls, ClassLoader loader,
AccessControlContext securityContext)
boolean error, AccessControlContext securityContext)
{
this.spi = spi;
this.urls = urls;
this.loader = loader;
this.securityContext = securityContext;
this.error = error;
this.nextProvider = loadNextServiceProvider();
}
@ -426,6 +485,9 @@ public final class ServiceFactory
log(Level.WARNING, "IOException upon reading {0}", currentURL,
readProblem);
line = null;
if (error)
throw new ServiceConfigurationError("Error reading " +
currentURL, readProblem);
}
/* When we are at the end of one list of services,
@ -477,6 +539,13 @@ public final class ServiceFactory
log(Level.WARNING, msg,
new Object[] { line, spi.getName(), currentURL },
ex);
if (error)
throw new ServiceConfigurationError("Cannot load service "+
"provider class " +
line + " specified by "+
"\"META-INF/services/"+
spi.getName() + "\" in "+
currentURL, ex);
continue;
}
}
@ -497,6 +566,9 @@ public final class ServiceFactory
catch (Exception ex)
{
log(Level.WARNING, "cannot close {0}", currentURL, ex);
if (error)
throw new ServiceConfigurationError("Cannot close " +
currentURL, ex);
}
reader = null;
currentURL = null;
@ -515,6 +587,9 @@ public final class ServiceFactory
catch (Exception ex)
{
log(Level.WARNING, "cannot open {0}", currentURL, ex);
if (error)
throw new ServiceConfigurationError("Cannot open " +
currentURL, ex);
}
}
while (reader == null);

View file

@ -1,5 +1,5 @@
/* VariableTable.java -- A class representing a Variable Table for a method
Copyright (C) 2005 Free Software Foundation
Copyright (C) 2005, 2007 Free Software Foundation
This file is part of GNU Classpath.

View file

@ -1,4 +1,4 @@
/* ArrayValue.java -- JDWP wrapper class for an Object value
/* ObjectValue.java -- JDWP wrapper class for an Object value
Copyright (C) 2007 Free Software Foundation
This file is part of GNU Classpath.

View file

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

View file

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

View file

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

View file

@ -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>&#x201c;Univers Light&#x201d;</i>.
@ -221,7 +228,8 @@ public interface FontDelegate
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics);
boolean fractionalMetrics,
int type);
/**

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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()
{
// TODO: Implement.
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)
{
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();
}
void computeSegments(int dim)
private void setWeakPoint(Point p)
{
// TODO: Implement.
p.setFlags((byte) (p.getFlags() | Point.FLAG_WEAK_INTERPOLATION));
}
void linkSegments(int dim)
/**
* Computes the inflection points for a glyph.
*/
private void computeInflectionPoints()
{
// TODO: Implement.
// 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;
}
public boolean doAlignStrongPoints()
{
return (flags & FontDelegate.FLAG_NO_HINT_STRONG_POINTS) == 0;
}
public boolean doAlignWeakPoints()
{
return (flags & FontDelegate.FLAG_NO_HINT_WEAK_POINTS) == 0;
}
}

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

@ -45,5 +45,9 @@ class ScriptMetrics
{
Script script;
Scaler scaler;
HintScaler scaler;
ScriptMetrics()
{
scaler = new HintScaler();
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -90,7 +90,8 @@ public abstract class Scaler
float pointSize,
AffineTransform transform,
boolean antialias,
boolean fractionalMetrics);
boolean fractionalMetrics,
Hinter hinter, int type);
/**

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
/**
@ -153,6 +150,11 @@ public abstract class AbstractGraphics2D
implements Cloneable
{
/**
* 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.
@ -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
@ -176,6 +185,11 @@ public abstract class AbstractGraphics2D
*/
private Paint paint;
/**
* The paint context during rendering.
*/
private PaintContext paintContext;
/**
* The 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);
}
/**
@ -1704,141 +1710,6 @@ public abstract class AbstractGraphics2D
throw new UnsupportedOperationException("Not implemented yet.");
}
/**
* 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();
}
/**
@ -2266,80 +1940,6 @@ public abstract class AbstractGraphics2D
p.transform(t);
}
/**
* 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.
*
* @return a list of PolyEdge that form the shape in device space
*/
private ArrayList getSegments(Shape s, AffineTransform t,
Rectangle2D deviceBounds, boolean isClip)
{
// 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())
{
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();
}
deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY);
return segs;
}
/**
* Returns the ShapeCache for the calling thread.
*
@ -2347,7 +1947,7 @@ public abstract class AbstractGraphics2D
*/
private ShapeCache getShapeCache()
{
ShapeCache sc = (ShapeCache) shapeCache.get();
ShapeCache sc = shapeCache.get();
if (sc == null)
{
sc = new ShapeCache();
@ -2355,4 +1955,20 @@ public abstract class AbstractGraphics2D
}
return sc;
}
/**
* Returns the scanline converter for this thread.
*
* @return the scanline converter for this thread
*/
private ScanlineConverter getScanlineConverter()
{
ScanlineConverter sc = scanlineConverters.get();
if (sc == null)
{
sc = new ScanlineConverter();
scanlineConverters.set(sc);
}
return sc;
}
}

View file

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

View file

@ -38,37 +38,62 @@ 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.
*/
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.
*
@ -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: "

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
@ -74,12 +74,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.
*/
@ -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;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;
DataFlavor flavor = flavors[i];
String mimeType = flavor.getMimeType();
mimeTargets[i] = mimeType;
if (! text)
if ("text".equals(flavor.getPrimaryType())
|| flavor.isRepresentationClassReader())
text = true;
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 (! 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;
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);
DataFlavor flavor = new DataFlavor(target);
Object o = contents.getTransferData(flavor);
if (o instanceof byte[])
return (byte[]) o;
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 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();
}
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(),

View file

@ -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.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.FontPeer;
import java.awt.peer.FramePeer;
import java.awt.peer.LabelPeer;
import java.awt.peer.ListPeer;
import java.awt.peer.MenuBarPeer;
import java.awt.peer.MenuItemPeer;
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 );

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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