Merged gcj-eclipse branch to trunk.
From-SVN: r120621
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/* WindowResizeEvent.java -- Used to synchronize the AWT and peer sizes
|
||||
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;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Component;
|
||||
|
||||
/**
|
||||
* This is used to update the AWT's knowledge about a Window's size when
|
||||
* the user changes the window bounds.
|
||||
*
|
||||
* This event is _not_ posted to the eventqueue, but rather dispatched directly
|
||||
* via Window.dispatchEvent(). It is the cleanest way we could find to update
|
||||
* the AWT's knowledge of the window size. Small testprograms showed the
|
||||
* following:
|
||||
* - Component.reshape() and its derivatives are _not_ called. This makes sense
|
||||
* as it could end up in loops,because this calls back into the peers.
|
||||
* - Intercepting event dispatching for any events in
|
||||
* EventQueue.dispatchEvent() showed that the size is still updated. So it
|
||||
* is not done via an event dispatched over the eventqueue.
|
||||
*
|
||||
* Possible other candidates for implementation would have been:
|
||||
* - Call a (private) callback method in Window/Component from the native
|
||||
* side.
|
||||
* - Call a (private) callback method in Window/Component via reflection.
|
||||
*
|
||||
* Both is uglier than sending this event directly. Note however that this
|
||||
* is impossible to test, as Component.dispatchEvent() is final and can't be
|
||||
* intercepted from outside code. But this impossibility to test the issue from
|
||||
* outside code also means that this shouldn't raise any compatibility issues.
|
||||
*/
|
||||
public class ComponentReshapeEvent
|
||||
extends AWTEvent
|
||||
{
|
||||
|
||||
public int x;
|
||||
public int y;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public ComponentReshapeEvent(Component c, int x, int y, int width, int height)
|
||||
{
|
||||
super(c, 1999);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* LowPriorityEvent.java -- Marks events with low priority
|
||||
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;
|
||||
|
||||
/**
|
||||
* A marker interface that marks events with low priority. LowPriority events
|
||||
* are dispatched _after_ other (normal priority) events by the EventQueue.
|
||||
*/
|
||||
public interface LowPriorityEvent
|
||||
{
|
||||
// Empty marker interface.
|
||||
}
|
||||
@@ -37,7 +37,6 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.color;
|
||||
|
||||
|
||||
/**
|
||||
* PyccConverter - conversion routines for the PhotoYCC colorspace
|
||||
*
|
||||
@@ -52,21 +51,21 @@ public class PyccConverter implements ColorSpaceConverter
|
||||
{
|
||||
public float[] toRGB(float[] in)
|
||||
{
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public float[] fromRGB(float[] in)
|
||||
{
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public float[] toCIEXYZ(float[] in)
|
||||
{
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public float[] fromCIEXYZ(float[] in)
|
||||
{
|
||||
return null;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,11 +61,13 @@ public class GtkDragSourceContextPeer
|
||||
private ComponentPeer peer;
|
||||
private Cursor cursor;
|
||||
private DragSourceContext context;
|
||||
public static Component target;
|
||||
|
||||
native void nativeStartDrag(Image i, int x, int y, int action, String target);
|
||||
native void connectSignals(ComponentPeer comp);
|
||||
native void create(ComponentPeer comp);
|
||||
native void nativeSetCursor(int cursor);
|
||||
native void setTarget(GtkDropTargetContextPeer target);
|
||||
|
||||
public GtkDragSourceContextPeer(DragGestureEvent e)
|
||||
{
|
||||
@@ -76,10 +78,18 @@ public class GtkDragSourceContextPeer
|
||||
create(peer);
|
||||
connectSignals(peer);
|
||||
cursor = comp.getCursor();
|
||||
|
||||
// FIXME: Where do we set the target?
|
||||
|
||||
if ((target != null))
|
||||
setTarget(new GtkDropTargetContextPeer(target));
|
||||
}
|
||||
|
||||
ComponentPeer getComponentPeer(Component c)
|
||||
{
|
||||
if (c == null)
|
||||
return null;
|
||||
|
||||
Component curr = c;
|
||||
while (curr.getPeer() instanceof LightweightPeer)
|
||||
curr = curr.getParent();
|
||||
@@ -93,7 +103,7 @@ public class GtkDragSourceContextPeer
|
||||
throws InvalidDnDOperationException
|
||||
{
|
||||
this.context = context;
|
||||
|
||||
|
||||
if (p == null)
|
||||
p = new Point();
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@ public class GtkDropTargetContextPeer
|
||||
extends GtkGenericPeer
|
||||
implements DropTargetContextPeer
|
||||
{
|
||||
|
||||
public GtkDropTargetContextPeer()
|
||||
|
||||
public GtkDropTargetContextPeer(Object obj)
|
||||
{
|
||||
super(null);
|
||||
super(obj);
|
||||
}
|
||||
|
||||
public void setTargetActions(int actions)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/* AxisHints.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;
|
||||
|
||||
class AxisHints
|
||||
{
|
||||
|
||||
Segment[] segments;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Constants.java -- Some constants used in 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;
|
||||
|
||||
/**
|
||||
* Some constants used in the autofitter.
|
||||
*/
|
||||
interface Constants
|
||||
{
|
||||
|
||||
/**
|
||||
* The horizontal dimension.
|
||||
*/
|
||||
static final int DIMENSION_HORZ = 0;
|
||||
|
||||
/**
|
||||
* The vertical dimension.
|
||||
*/
|
||||
static final int DIMENSION_VERT = 1;
|
||||
|
||||
/**
|
||||
* The number of dimensions.
|
||||
*/
|
||||
static final int DIMENSION_MAX = 2;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/* GlyphHints.java -- Data and methods for actual hinting
|
||||
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.Zone;
|
||||
|
||||
/**
|
||||
* The data and methods used for the actual hinting process.
|
||||
*/
|
||||
class GlyphHints
|
||||
{
|
||||
|
||||
int xScale;
|
||||
int xDelta;
|
||||
int yScale;
|
||||
int yDelta;
|
||||
|
||||
AxisHints[] axis;
|
||||
|
||||
void rescale(ScriptMetrics metrics)
|
||||
{
|
||||
// TODO: Implement.
|
||||
}
|
||||
|
||||
void reload(Zone outline)
|
||||
{
|
||||
// TODO: Implement.
|
||||
}
|
||||
|
||||
void computeSegments(int dim)
|
||||
{
|
||||
// TODO: Implement.
|
||||
}
|
||||
|
||||
void linkSegments(int dim)
|
||||
{
|
||||
// TODO: Implement.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/* Latin.java -- Latin specific glyph handling
|
||||
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 java.awt.geom.AffineTransform;
|
||||
|
||||
import gnu.java.awt.font.opentype.OpenTypeFont;
|
||||
import gnu.java.awt.font.opentype.truetype.Zone;
|
||||
|
||||
/**
|
||||
* Implements Latin specific glyph handling.
|
||||
*/
|
||||
class Latin
|
||||
implements Script, Constants
|
||||
{
|
||||
|
||||
private static final int MAX_WIDTHS = 16;
|
||||
|
||||
public void applyHints(GlyphHints hints, ScriptMetrics metrics)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void doneMetrics(ScriptMetrics metrics)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the <code>hints</code> object.
|
||||
*
|
||||
* @param hints the hints to initialize
|
||||
* @param metrics the metrics to use
|
||||
*/
|
||||
public void initHints(GlyphHints hints, ScriptMetrics metrics)
|
||||
{
|
||||
hints.rescale(metrics);
|
||||
LatinMetrics lm = (LatinMetrics) metrics;
|
||||
hints.xScale = lm.axis[DIMENSION_HORZ].scale;
|
||||
hints.xDelta = lm.axis[DIMENSION_HORZ].delta;
|
||||
hints.yScale = lm.axis[DIMENSION_VERT].scale;
|
||||
hints.yDelta = lm.axis[DIMENSION_VERT].delta;
|
||||
// TODO: Set the scaler and other flags.
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the script metrics.
|
||||
*
|
||||
* @param metrics the script metrics to initialize
|
||||
* @param face the font
|
||||
*/
|
||||
public void initMetrics(ScriptMetrics metrics, OpenTypeFont face)
|
||||
{
|
||||
assert metrics instanceof LatinMetrics;
|
||||
LatinMetrics lm = (LatinMetrics) metrics;
|
||||
lm.unitsPerEm = face.unitsPerEm;
|
||||
|
||||
// TODO: Check for latin charmap.
|
||||
|
||||
initWidths(lm, face, 'o');
|
||||
initBlues(lm, face);
|
||||
}
|
||||
|
||||
public void scaleMetrics(ScriptMetrics metrics)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the standard stem widths.
|
||||
*
|
||||
* @param metrics the metrics to use
|
||||
* @param face the font face
|
||||
* @param ch the character that is used for getting the widths
|
||||
*/
|
||||
private void initWidths(LatinMetrics metrics, OpenTypeFont face, char ch)
|
||||
{
|
||||
GlyphHints hints = new GlyphHints();
|
||||
metrics.axis[DIMENSION_HORZ].widthCount = 0;
|
||||
metrics.axis[DIMENSION_VERT].widthCount = 0;
|
||||
int glyphIndex = face.getGlyph(ch);
|
||||
// TODO: Avoid that AffineTransform constructor and change
|
||||
// getRawGlyphOutline() to accept null or remove that parameter altogether.
|
||||
// Consider this when the thing is done and we know what we need that for.
|
||||
Zone outline = face.getRawGlyphOutline(glyphIndex, new AffineTransform());
|
||||
LatinMetrics dummy = new LatinMetrics();
|
||||
Scaler scaler = dummy.scaler;
|
||||
dummy.unitsPerEm = metrics.unitsPerEm;
|
||||
scaler.xScale = scaler.yScale = 10000;
|
||||
scaler.xDelta = scaler.yDelta = 0;
|
||||
scaler.face = face;
|
||||
hints.rescale(dummy);
|
||||
hints.reload(outline);
|
||||
for (int dim = 0; dim < DIMENSION_MAX; dim++)
|
||||
{
|
||||
LatinAxis axis = metrics.axis[dim];
|
||||
AxisHints axHints = hints.axis[dim];
|
||||
int numWidths = 0;
|
||||
hints.computeSegments(dim);
|
||||
hints.linkSegments(dim);
|
||||
Segment[] segs = axHints.segments;
|
||||
for (int i = 0; i < segs.length; i++)
|
||||
{
|
||||
Segment seg = segs[i];
|
||||
Segment link = seg.link;
|
||||
if (link != null && link.link == seg && link.index > i)
|
||||
{
|
||||
int dist = Math.abs(seg.pos - link.pos);
|
||||
if (numWidths < MAX_WIDTHS)
|
||||
axis.widths[numWidths++].org = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int dim = 0; dim < DIMENSION_MAX; dim++)
|
||||
{
|
||||
LatinAxis axis = metrics.axis[dim];
|
||||
int stdw = axis.widthCount > 0 ? axis.widths[0].org
|
||||
: constant(metrics, 50);
|
||||
axis.edgeDistanceTreshold= stdw / 5;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the blue zones of the font.
|
||||
*
|
||||
* @param metrics the metrics to use
|
||||
* @param face the font face to analyze
|
||||
*/
|
||||
private void initBlues(LatinMetrics metrics, OpenTypeFont face)
|
||||
{
|
||||
// TODO: Implement.
|
||||
}
|
||||
|
||||
private int constant(LatinMetrics metrics, int c)
|
||||
{
|
||||
return c * (metrics.unitsPerEm / 2048);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* LatinAxis.java -- Axis specific data
|
||||
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;
|
||||
|
||||
/**
|
||||
* Some axis specific data.
|
||||
*/
|
||||
class LatinAxis
|
||||
{
|
||||
|
||||
int scale;
|
||||
int delta;
|
||||
|
||||
int widthCount;
|
||||
Width[] widths;
|
||||
float edgeDistanceTreshold;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/* LatinMetrics.java -- Latin specific metrics data
|
||||
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;
|
||||
|
||||
/**
|
||||
* Latin specific metrics data.
|
||||
*/
|
||||
class LatinMetrics
|
||||
extends ScriptMetrics
|
||||
{
|
||||
|
||||
LatinAxis[] axis;
|
||||
|
||||
int unitsPerEm;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* Scaler.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;
|
||||
|
||||
import gnu.java.awt.font.opentype.OpenTypeFont;
|
||||
|
||||
class Scaler
|
||||
{
|
||||
|
||||
int xScale;
|
||||
int xDelta;
|
||||
int yScale;
|
||||
int yDelta;
|
||||
OpenTypeFont face;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Script.java -- Defines script specific interface to 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.OpenTypeFont;
|
||||
|
||||
/**
|
||||
* Defines script specific methods for the auto fitter.
|
||||
*/
|
||||
interface Script
|
||||
{
|
||||
|
||||
/**
|
||||
* Initializes the metrics.
|
||||
*/
|
||||
void initMetrics(ScriptMetrics metrics, OpenTypeFont face);
|
||||
|
||||
void scaleMetrics(ScriptMetrics metrics/* , scaler, map this */);
|
||||
|
||||
void doneMetrics(ScriptMetrics metrics);
|
||||
|
||||
void initHints(GlyphHints hints, ScriptMetrics metrics);
|
||||
|
||||
void applyHints(GlyphHints hints, /* some outline object, */
|
||||
ScriptMetrics metrics);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* ScriptMetrics.java -- Script specific metrics data
|
||||
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;
|
||||
|
||||
/**
|
||||
* Script specific metrics data.
|
||||
*/
|
||||
class ScriptMetrics
|
||||
{
|
||||
|
||||
Script script;
|
||||
Scaler scaler;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* Segment.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;
|
||||
|
||||
class Segment
|
||||
{
|
||||
|
||||
Segment link;
|
||||
int index;
|
||||
int pos;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Width.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 Width
|
||||
{
|
||||
int org;
|
||||
int cur;
|
||||
int fit;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ import java.nio.IntBuffer;
|
||||
*
|
||||
* @author Sascha Brawer (brawer@dandelis.ch)
|
||||
*/
|
||||
abstract class CharGlyphMap
|
||||
public abstract class CharGlyphMap
|
||||
{
|
||||
private static final int PLATFORM_UNICODE = 0;
|
||||
private static final int PLATFORM_MACINTOSH = 1;
|
||||
|
||||
@@ -52,6 +52,7 @@ import java.util.Locale;
|
||||
import gnu.java.awt.font.FontDelegate;
|
||||
import gnu.java.awt.font.GNUGlyphVector;
|
||||
import gnu.java.awt.font.opentype.truetype.TrueTypeScaler;
|
||||
import gnu.java.awt.font.opentype.truetype.Zone;
|
||||
|
||||
|
||||
/**
|
||||
@@ -117,7 +118,7 @@ public final class OpenTypeFont
|
||||
* OpenType fonts with PostScript outlines, other values are
|
||||
* acceptable (such as 1000).
|
||||
*/
|
||||
private int unitsPerEm;
|
||||
public int unitsPerEm;
|
||||
|
||||
|
||||
/**
|
||||
@@ -697,6 +698,20 @@ public final class OpenTypeFont
|
||||
antialias, fractionalMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the raw glyph outline for the specified glyph index. This is used
|
||||
* for the autofitter only ATM and is otherwise not usable for outside code.
|
||||
*
|
||||
* @param glyph the glyph index to fetch
|
||||
* @param transform the transform to apply
|
||||
*
|
||||
* @return the raw outline of that glyph
|
||||
*/
|
||||
public synchronized Zone getRawGlyphOutline(int glyph,
|
||||
AffineTransform transform)
|
||||
{
|
||||
return scaler.getRawOutline(glyph, transform);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the specified glyph. This is useful for
|
||||
|
||||
@@ -37,6 +37,8 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.font.opentype;
|
||||
|
||||
import gnu.java.awt.font.opentype.truetype.Zone;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
@@ -189,4 +191,14 @@ public abstract class Scaler
|
||||
boolean antialiased,
|
||||
boolean fractionalMetrics,
|
||||
boolean horizontal);
|
||||
|
||||
/**
|
||||
* Returns the raw outline data. This is used for the autofitter atm.
|
||||
*
|
||||
* @param glyph the glyph index
|
||||
* @param transform the transform to apply
|
||||
*
|
||||
* @return the raw glyph outline
|
||||
*/
|
||||
public abstract Zone getRawOutline(int glyph, AffineTransform transform);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,11 @@ final class GlyphLoader
|
||||
0, 0);
|
||||
}
|
||||
|
||||
public void loadGlyph(int glyphIndex, AffineTransform transform,
|
||||
Zone glyphZone)
|
||||
{
|
||||
loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone);
|
||||
}
|
||||
|
||||
private void loadSubGlyph(int glyphIndex,
|
||||
double pointSize,
|
||||
|
||||
@@ -198,6 +198,12 @@ public final class TrueTypeScaler
|
||||
return glyphZone.getPath();
|
||||
}
|
||||
|
||||
public Zone getRawOutline(int glyphIndex, AffineTransform transform)
|
||||
{
|
||||
Zone zone = new Zone(glyphZone.getCapacity());
|
||||
glyphLoader.loadGlyph(glyphIndex, transform, zone);
|
||||
return zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the advance width and height for a glyph.
|
||||
|
||||
@@ -45,7 +45,7 @@ import java.awt.geom.PathIterator;
|
||||
/**
|
||||
* A collection of points with some additional information.
|
||||
*/
|
||||
final class Zone
|
||||
public final class Zone
|
||||
{
|
||||
private final int[] pos;
|
||||
private final int[] origPos;
|
||||
|
||||
@@ -100,6 +100,20 @@ import java.util.Map;
|
||||
* {@link #updateRaster(Raster, int, int, int, int)} method, which always gets
|
||||
* called after a chunk of data got painted into the raster.
|
||||
* </p>
|
||||
* <p>Alternativly the backend can provide a method for filling Shapes by
|
||||
* overriding the protected method fillShape(). This can be accomplished
|
||||
* by a polygon filling function of the backend. Keep in mind though that
|
||||
* Shapes can be quite complex (i.e. non-convex and containing holes, etc)
|
||||
* which is not supported by all polygon fillers. Also it must be noted
|
||||
* that fillShape() is expected to handle painting and compositing as well as
|
||||
* clipping and transformation. If your backend can't support this natively,
|
||||
* then you can fallback to the implementation in this class. You'll need
|
||||
* to provide a writable Raster then, see above.</p>
|
||||
* <p>Another alternative is to implement fillScanline() which only requires
|
||||
* the backend to be able to draw horizontal lines in device space,
|
||||
* which is usually very cheap.
|
||||
* The implementation should still handle painting and compositing,
|
||||
* but no more clipping and transformation is required by the backend.</p>
|
||||
* <p>The backend is free to provide implementations for the various raw*
|
||||
* methods for optimized AWT 1.1 style painting of some primitives. This should
|
||||
* accelerate painting of Swing greatly. When doing so, the backend must also
|
||||
@@ -126,6 +140,9 @@ import java.util.Map;
|
||||
* in plain Java because they involve lots of shuffling around with large
|
||||
* arrays. In fact, you really would want to let the graphics card to the
|
||||
* work, they are made for this.</li>
|
||||
* <li>Provide an accelerated implementation for fillShape(). For instance,
|
||||
* OpenGL can fill shapes very efficiently. There are some considerations
|
||||
* to be made though, see above for details.</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
@@ -143,6 +160,12 @@ public abstract class AbstractGraphics2D
|
||||
*/
|
||||
private static final int AA_SAMPLING = 8;
|
||||
|
||||
/**
|
||||
* Caches certain shapes to avoid massive creation of such Shapes in
|
||||
* the various draw* and fill* methods.
|
||||
*/
|
||||
private static final ThreadLocal shapeCache = new ThreadLocal();
|
||||
|
||||
/**
|
||||
* The transformation for this Graphics2D instance
|
||||
*/
|
||||
@@ -183,11 +206,6 @@ public abstract class AbstractGraphics2D
|
||||
*/
|
||||
private RenderingHints renderingHints;
|
||||
|
||||
/**
|
||||
* The paint raster.
|
||||
*/
|
||||
private Raster paintRaster;
|
||||
|
||||
/**
|
||||
* The raster of the destination surface. This is where the painting is
|
||||
* performed.
|
||||
@@ -219,7 +237,7 @@ public abstract class AbstractGraphics2D
|
||||
* AbstractGraphics2D object and will be the most commonly used setting
|
||||
* in Swing rendering and should therefore be optimized as much as possible.
|
||||
*/
|
||||
private boolean isOptimized;
|
||||
private boolean isOptimized = true;
|
||||
|
||||
/**
|
||||
* Creates a new AbstractGraphics2D instance.
|
||||
@@ -270,7 +288,6 @@ public abstract class AbstractGraphics2D
|
||||
public boolean drawImage(Image image, AffineTransform xform,
|
||||
ImageObserver obs)
|
||||
{
|
||||
boolean ret = false;
|
||||
Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs),
|
||||
image.getHeight(obs));
|
||||
return drawImageImpl(image, xform, obs, areaOfInterest);
|
||||
@@ -982,7 +999,8 @@ public abstract class AbstractGraphics2D
|
||||
else
|
||||
copy.clip = new GeneralPath(clip);
|
||||
|
||||
copy.renderingHints = new RenderingHints(renderingHints);
|
||||
copy.renderingHints = new RenderingHints(null);
|
||||
copy.renderingHints.putAll(renderingHints);
|
||||
copy.transform = new AffineTransform(transform);
|
||||
// The remaining state is inmmutable and doesn't need to be copied.
|
||||
return copy;
|
||||
@@ -1143,14 +1161,31 @@ public abstract class AbstractGraphics2D
|
||||
{
|
||||
if (isOptimized)
|
||||
{
|
||||
int tx = (int) transform.getTranslateX();
|
||||
int ty = (int) transform.getTranslateY();
|
||||
rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty);
|
||||
rawDrawLine(x1, y1, x2, y2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Line2D line = new Line2D.Double(x1, y1, x2, y2);
|
||||
draw(line);
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.line == null)
|
||||
sc.line = new Line2D.Float();
|
||||
sc.line.setLine(x1, y1, x2, y2);
|
||||
draw(sc.line);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRect(int x, int y, int w, int h)
|
||||
{
|
||||
if (isOptimized)
|
||||
{
|
||||
rawDrawRect(x, y, w, h);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.rect == null)
|
||||
sc.rect = new Rectangle();
|
||||
sc.rect.setBounds(x, y, w, h);
|
||||
draw(sc.rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,13 +1201,15 @@ public abstract class AbstractGraphics2D
|
||||
{
|
||||
if (isOptimized)
|
||||
{
|
||||
int tx = (int) transform.getTranslateX();
|
||||
int ty = (int) transform.getTranslateY();
|
||||
rawFillRect(x + tx, y + ty, width, height);
|
||||
rawFillRect(x, y, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
fill(new Rectangle(x, y, width, height));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.rect == null)
|
||||
sc.rect = new Rectangle();
|
||||
sc.rect.setBounds(x, y, width, height);
|
||||
fill(sc.rect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1213,8 +1250,11 @@ public abstract class AbstractGraphics2D
|
||||
public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
|
||||
int arcHeight)
|
||||
{
|
||||
draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
|
||||
arcHeight));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.roundRect == null)
|
||||
sc.roundRect = new RoundRectangle2D.Float();
|
||||
sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
|
||||
draw(sc.roundRect);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1230,8 +1270,11 @@ public abstract class AbstractGraphics2D
|
||||
public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
|
||||
int arcHeight)
|
||||
{
|
||||
fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth,
|
||||
arcHeight));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.roundRect == null)
|
||||
sc.roundRect = new RoundRectangle2D.Float();
|
||||
sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
|
||||
fill(sc.roundRect);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1244,7 +1287,11 @@ public abstract class AbstractGraphics2D
|
||||
*/
|
||||
public void drawOval(int x, int y, int width, int height)
|
||||
{
|
||||
draw(new Ellipse2D.Double(x, y, width, height));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.ellipse == null)
|
||||
sc.ellipse = new Ellipse2D.Float();
|
||||
sc.ellipse.setFrame(x, y, width, height);
|
||||
draw(sc.ellipse);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1257,7 +1304,11 @@ public abstract class AbstractGraphics2D
|
||||
*/
|
||||
public void fillOval(int x, int y, int width, int height)
|
||||
{
|
||||
fill(new Ellipse2D.Double(x, y, width, height));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.ellipse == null)
|
||||
sc.ellipse = new Ellipse2D.Float();
|
||||
sc.ellipse.setFrame(x, y, width, height);
|
||||
fill(sc.ellipse);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1266,8 +1317,11 @@ public abstract class AbstractGraphics2D
|
||||
public void drawArc(int x, int y, int width, int height, int arcStart,
|
||||
int arcAngle)
|
||||
{
|
||||
draw(new Arc2D.Double(x, y, width, height, arcStart, arcAngle,
|
||||
Arc2D.OPEN));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.arc == null)
|
||||
sc.arc = new Arc2D.Float();
|
||||
sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN);
|
||||
draw(sc.arc);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1276,8 +1330,11 @@ public abstract class AbstractGraphics2D
|
||||
public void fillArc(int x, int y, int width, int height, int arcStart,
|
||||
int arcAngle)
|
||||
{
|
||||
fill(new Arc2D.Double(x, y, width, height, arcStart, arcAngle,
|
||||
Arc2D.OPEN));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.arc == null)
|
||||
sc.arc = new Arc2D.Float();
|
||||
sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE);
|
||||
draw(sc.arc);
|
||||
}
|
||||
|
||||
public void drawPolyline(int[] xPoints, int[] yPoints, int npoints)
|
||||
@@ -1291,7 +1348,13 @@ public abstract class AbstractGraphics2D
|
||||
*/
|
||||
public void drawPolygon(int[] xPoints, int[] yPoints, int npoints)
|
||||
{
|
||||
draw(new Polygon(xPoints, yPoints, npoints));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.polygon == null)
|
||||
sc.polygon = new Polygon();
|
||||
sc.polygon.xpoints = xPoints;
|
||||
sc.polygon.ypoints = yPoints;
|
||||
sc.polygon.npoints = npoints;
|
||||
draw(sc.polygon);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1299,7 +1362,13 @@ public abstract class AbstractGraphics2D
|
||||
*/
|
||||
public void fillPolygon(int[] xPoints, int[] yPoints, int npoints)
|
||||
{
|
||||
fill(new Polygon(xPoints, yPoints, npoints));
|
||||
ShapeCache sc = getShapeCache();
|
||||
if (sc.polygon == null)
|
||||
sc.polygon = new Polygon();
|
||||
sc.polygon.xpoints = xPoints;
|
||||
sc.polygon.ypoints = yPoints;
|
||||
sc.polygon.npoints = npoints;
|
||||
fill(sc.polygon);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1460,8 +1529,12 @@ public abstract class AbstractGraphics2D
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the specified shape. The shape has already been clipped against the
|
||||
* current clip.
|
||||
* Fills the specified shape. Override this if your backend can efficiently
|
||||
* fill shapes. This is possible on many systems via a polygon fill
|
||||
* method or something similar. But keep in mind that Shapes can be quite
|
||||
* complex (non-convex, with holes etc), which is not necessarily supported
|
||||
* by all polygon fillers. Also note that you must perform clipping
|
||||
* before filling the shape.
|
||||
*
|
||||
* @param s the shape to fill
|
||||
* @param isFont <code>true</code> if the shape is a font outline
|
||||
@@ -1533,6 +1606,11 @@ public abstract class AbstractGraphics2D
|
||||
draw(new Line2D.Float(x0, y0, x1, y1));
|
||||
}
|
||||
|
||||
protected void rawDrawRect(int x, int y, int w, int h)
|
||||
{
|
||||
draw(new Rectangle(x, y, w, h));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a string in optimization mode. The implementation should respect the
|
||||
* clip and translation. It can assume that the clip is a rectangle and that
|
||||
@@ -1627,11 +1705,7 @@ public abstract class AbstractGraphics2D
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the specified polygon. This should be overridden by backends
|
||||
* that support accelerated (native) polygon filling, which is the
|
||||
* case for most toolkit window and offscreen image implementations.
|
||||
*
|
||||
* The polygon is already clipped when this method is called.
|
||||
* Fills the specified polygon without anti-aliasing.
|
||||
*/
|
||||
private void fillShapeImpl(ArrayList segs, Rectangle2D deviceBounds2D,
|
||||
Rectangle2D userBounds,
|
||||
@@ -1662,7 +1736,7 @@ public abstract class AbstractGraphics2D
|
||||
for (Iterator i = segs.iterator(); i.hasNext();)
|
||||
{
|
||||
PolyEdge edge = (PolyEdge) i.next();
|
||||
int yindex = (int) ((int) Math.ceil(edge.y0) - (int) Math.ceil(icMinY));
|
||||
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.
|
||||
@@ -1766,7 +1840,8 @@ public abstract class AbstractGraphics2D
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints a scanline between x0 and x1.
|
||||
* Paints a scanline between x0 and x1. Override this when your backend
|
||||
* can efficiently draw/fill horizontal lines.
|
||||
*
|
||||
* @param x0 the left offset
|
||||
* @param x1 the right offset
|
||||
@@ -1972,8 +2047,7 @@ public abstract class AbstractGraphics2D
|
||||
// Render full scanline.
|
||||
//System.err.println("scanline: " + y);
|
||||
if (! emptyScanline)
|
||||
fillScanlineAA(alpha, leftX, (int) y, rightX - leftX, pCtx,
|
||||
(int) minX);
|
||||
fillScanlineAA(alpha, leftX, y, rightX - leftX, pCtx, (int) minX);
|
||||
}
|
||||
|
||||
pCtx.dispose();
|
||||
@@ -1986,7 +2060,7 @@ public abstract class AbstractGraphics2D
|
||||
*
|
||||
* @param alpha the alpha values in the scanline
|
||||
* @param x0 the beginning of the scanline
|
||||
* @param y the y coordinate of the line
|
||||
* @param yy the y coordinate of the line
|
||||
*/
|
||||
private void fillScanlineAA(int[] alpha, int x0, int yy, int numPixels,
|
||||
PaintContext pCtx, int offs)
|
||||
@@ -1997,7 +2071,6 @@ public abstract class AbstractGraphics2D
|
||||
Raster paintRaster = pCtx.getRaster(x0, yy, numPixels, 1);
|
||||
//System.err.println("paintColorModel: " + pCtx.getColorModel());
|
||||
WritableRaster aaRaster = paintRaster.createCompatibleWritableRaster();
|
||||
int numBands = paintRaster.getNumBands();
|
||||
ColorModel cm = pCtx.getColorModel();
|
||||
double lastAlpha = 0.;
|
||||
int lastAlphaInt = 0;
|
||||
@@ -2156,10 +2229,10 @@ public abstract class AbstractGraphics2D
|
||||
private static Rectangle computeIntersection(int x, int y, int w, int h,
|
||||
Rectangle rect)
|
||||
{
|
||||
int x2 = (int) rect.x;
|
||||
int y2 = (int) rect.y;
|
||||
int w2 = (int) rect.width;
|
||||
int h2 = (int) rect.height;
|
||||
int x2 = rect.x;
|
||||
int y2 = rect.y;
|
||||
int w2 = rect.width;
|
||||
int h2 = rect.height;
|
||||
|
||||
int dx = (x > x2) ? x : x2;
|
||||
int dy = (y > y2) ? y : y2;
|
||||
@@ -2266,4 +2339,20 @@ public abstract class AbstractGraphics2D
|
||||
deviceBounds.setRect(minX, minY, maxX - minX, maxY - minY);
|
||||
return segs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ShapeCache for the calling thread.
|
||||
*
|
||||
* @return the ShapeCache for the calling thread
|
||||
*/
|
||||
private ShapeCache getShapeCache()
|
||||
{
|
||||
ShapeCache sc = (ShapeCache) shapeCache.get();
|
||||
if (sc == null)
|
||||
{
|
||||
sc = new ShapeCache();
|
||||
shapeCache.set(sc);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,52 @@ public class QuadSegment extends Segment
|
||||
|
||||
Point2D cp;
|
||||
QuadSegment s;
|
||||
if( plus )
|
||||
if(!plus)
|
||||
{
|
||||
n1[0] = -n1[0];
|
||||
n1[1] = -n1[1];
|
||||
n2[0] = -n2[0];
|
||||
n2[1] = -n2[1];
|
||||
}
|
||||
|
||||
// Handle special cases where the control point is equal to an end point
|
||||
// or end points are equal (ie, straight lines)
|
||||
if (curve.getP1().equals(curve.getCtrlPt()))
|
||||
{
|
||||
cp = curve.getCtrlPt();
|
||||
cp.setLocation(cp.getX() + n2[0], cp.getY() + n2[1]);
|
||||
n1[0] = n2[0];
|
||||
n1[1] = n2[1];
|
||||
}
|
||||
else if (curve.getP2().equals(curve.getCtrlPt()))
|
||||
{
|
||||
cp = curve.getCtrlPt();
|
||||
cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]);
|
||||
n2[0] = n1[0];
|
||||
n2[1] = n1[1];
|
||||
}
|
||||
else if (curve.getP1().equals(curve.getP2()))
|
||||
{
|
||||
cp = curve.getCtrlPt();
|
||||
|
||||
double deltaX = curve.getX1() - curve.getCtrlX();
|
||||
double deltaY = curve.getY1() - curve.getCtrlY();
|
||||
double length = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
|
||||
double ratio = radius / length;
|
||||
deltaX *= ratio;
|
||||
deltaY *= ratio;
|
||||
|
||||
if (plus)
|
||||
cp.setLocation(cp.getX() + deltaX, cp.getY() + deltaY);
|
||||
else
|
||||
cp.setLocation(cp.getX() - deltaX, cp.getY() - deltaY);
|
||||
}
|
||||
else if (n1[0] == n2[0] && n1[1] == n2[1])
|
||||
{
|
||||
cp = curve.getCtrlPt();
|
||||
cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
cp = lineIntersection(curve.getX1() + n1[0],
|
||||
curve.getY1() + n1[1],
|
||||
@@ -155,25 +200,11 @@ public class QuadSegment extends Segment
|
||||
curve.getCtrlY() + n2[1],
|
||||
curve.getX2() + n2[0],
|
||||
curve.getY2() + n2[1], true);
|
||||
s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
|
||||
cp.getX(), cp.getY(),
|
||||
curve.getX2() + n2[0], curve.getY2() + n2[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
cp = lineIntersection(curve.getX1() - n1[0],
|
||||
curve.getY1() - n1[1],
|
||||
curve.getCtrlX() - n1[0],
|
||||
curve.getCtrlY() - n1[1],
|
||||
curve.getCtrlX() - n2[0],
|
||||
curve.getCtrlY() - n2[1],
|
||||
curve.getX2() - n2[0],
|
||||
curve.getY2() - n2[1], true);
|
||||
|
||||
s = new QuadSegment(curve.getX1() - n1[0], curve.getY1() - n1[1],
|
||||
cp.getX(), cp.getY(),
|
||||
curve.getX2() - n2[0], curve.getY2() - n2[1]);
|
||||
}
|
||||
|
||||
s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1],
|
||||
cp.getX(), cp.getY(),
|
||||
curve.getX2() + n2[0], curve.getY2() + n2[1]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* ShapeCache.java -- Caches certain Shapes for reuse in AbstractGraphics2D
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.java2d;
|
||||
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
/**
|
||||
* Caches certain Shape objects for reuse in AbstractGraphics2D. This avoids
|
||||
* massive creation of such objects.
|
||||
*/
|
||||
public class ShapeCache
|
||||
{
|
||||
|
||||
/**
|
||||
* A cached Line2D.
|
||||
*/
|
||||
public Line2D line;
|
||||
|
||||
/**
|
||||
* A cached Rectangle.
|
||||
*/
|
||||
public Rectangle rect;
|
||||
|
||||
/**
|
||||
* A cached RoundRectangle2D.
|
||||
*/
|
||||
public RoundRectangle2D roundRect;
|
||||
|
||||
/**
|
||||
* A cached Ellipse2D.
|
||||
*/
|
||||
public Ellipse2D ellipse;
|
||||
|
||||
/**
|
||||
* A cached Arc2D.
|
||||
*/
|
||||
public Arc2D arc;
|
||||
|
||||
/**
|
||||
* A cached Polygon.
|
||||
*/
|
||||
public Polygon polygon;
|
||||
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class TexturePaintContext
|
||||
double scaleY = anchor.getHeight() / image.getHeight();
|
||||
transform = (AffineTransform) xform.clone();
|
||||
transform.scale(scaleX, scaleY);
|
||||
transform.translate(-anchor.getMinX(), -anchor.getMaxX());
|
||||
transform.translate(-anchor.getMinX(), -anchor.getMinY());
|
||||
transform = transform.createInverse();
|
||||
}
|
||||
catch (NoninvertibleTransformException ex)
|
||||
@@ -177,6 +177,12 @@ public class TexturePaintContext
|
||||
// The modulo operation gives us the replication effect.
|
||||
dx = ((dx - minX) % width) + minX;
|
||||
dy = ((dy - minY) % height) + minY;
|
||||
|
||||
// Handle possible negative values (replicating above the top-left)
|
||||
if (dx < 0)
|
||||
dx += width;
|
||||
if (dy < 0)
|
||||
dy += height;
|
||||
|
||||
// Copy the pixel.
|
||||
pixel = source.getDataElements(dx, dy, pixel);
|
||||
|
||||
@@ -832,18 +832,4 @@ public abstract class ClasspathFontPeer
|
||||
public abstract Rectangle2D getMaxCharBounds (Font font,
|
||||
FontRenderContext rc);
|
||||
|
||||
/**
|
||||
* Implementation of {@link Font#getStringBounds(CharacterIterator, int,
|
||||
* int, FontRenderContext)}
|
||||
*
|
||||
* @param font the font this peer is being called from. This may be
|
||||
* useful if you are sharing peers between Font objects. Otherwise it may
|
||||
* be ignored.
|
||||
*/
|
||||
|
||||
public abstract Rectangle2D getStringBounds (Font font,
|
||||
CharacterIterator ci,
|
||||
int begin, int limit,
|
||||
FontRenderContext frc);
|
||||
|
||||
}
|
||||
|
||||
@@ -54,25 +54,14 @@ import java.awt.Insets;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.PaintEvent;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.ContainerPeer;
|
||||
import java.awt.peer.LightweightPeer;
|
||||
|
||||
/*
|
||||
* Another possible implementation strategy for lightweight peers is
|
||||
* to make GLightweightPeer a placeholder class that implements
|
||||
* LightweightPeer. Then the Component and Container classes could
|
||||
* identify a peer as lightweight and handle it specially. The
|
||||
* current approach is probably more clear but less efficient.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A stub class that implements the ComponentPeer and ContainerPeer
|
||||
* interfaces using callbacks into the Component and Container
|
||||
@@ -85,47 +74,48 @@ import java.awt.peer.LightweightPeer;
|
||||
public class GLightweightPeer
|
||||
implements LightweightPeer, ContainerPeer
|
||||
{
|
||||
private Component comp;
|
||||
|
||||
private Insets containerInsets;
|
||||
|
||||
public GLightweightPeer(Component comp)
|
||||
public GLightweightPeer()
|
||||
{
|
||||
this.comp = comp;
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
// -------- java.awt.peer.ContainerPeer implementation:
|
||||
|
||||
public Insets insets()
|
||||
{
|
||||
return getInsets ();
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public Insets getInsets()
|
||||
{
|
||||
if (containerInsets == null)
|
||||
containerInsets = new Insets (0,0,0,0);
|
||||
return containerInsets;
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void beginValidate()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void endValidate()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void beginLayout()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void endLayout()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public boolean isPaintPending()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -133,122 +123,188 @@ public class GLightweightPeer
|
||||
|
||||
public int checkImage(Image img, int width, int height, ImageObserver o)
|
||||
{
|
||||
return comp.getToolkit().checkImage(img, width, height, o);
|
||||
// Nothing to do here for lightweights.
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Image createImage(ImageProducer prod)
|
||||
{
|
||||
return comp.getToolkit().createImage(prod);
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
/* This method is not called. */
|
||||
public Image createImage(int width, int height)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void disable() {}
|
||||
public void disable()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void dispose() {}
|
||||
public void dispose()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void enable() {}
|
||||
public void enable()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public GraphicsConfiguration getGraphicsConfiguration()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public FontMetrics getFontMetrics(Font f)
|
||||
{
|
||||
return comp.getToolkit().getFontMetrics(f);
|
||||
// We shouldn't end up here, but if we do we can still try do something
|
||||
// reasonable.
|
||||
Toolkit tk = Toolkit.getDefaultToolkit();
|
||||
return tk.getFontMetrics(f);
|
||||
}
|
||||
|
||||
/* Returning null here tells the Component object that called us to
|
||||
* use its parent's Graphics. */
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public Point getLocationOnScreen()
|
||||
{
|
||||
Point parentLocation = comp.getParent().getLocationOnScreen();
|
||||
return new Point (parentLocation.x + comp.getX(),
|
||||
parentLocation.y + comp.getY());
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize()
|
||||
{
|
||||
return new Dimension(comp.getWidth(), comp.getHeight());
|
||||
return minimumSize();
|
||||
}
|
||||
|
||||
/* A lightweight component's preferred size is equivalent to its
|
||||
* Component width and height values. */
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(comp.getWidth(), comp.getHeight());
|
||||
return preferredSize();
|
||||
}
|
||||
|
||||
/* Returning null here tells the Component object that called us to
|
||||
* use its parent's Toolkit. */
|
||||
public Toolkit getToolkit()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleEvent(AWTEvent e) {}
|
||||
public void handleEvent(AWTEvent e)
|
||||
{
|
||||
// This can only happen when an application posts a PaintEvent for
|
||||
// a lightweight component directly. We still support painting for
|
||||
// this case.
|
||||
if (e instanceof PaintEvent)
|
||||
{
|
||||
PaintEvent pe = (PaintEvent) e;
|
||||
Component target = (Component) e.getSource();
|
||||
if (target != null && target.isShowing())
|
||||
{
|
||||
Graphics g = target.getGraphics();
|
||||
if (g != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Rectangle clip = pe.getUpdateRect();
|
||||
g.setClip(clip);
|
||||
target.paint(g);
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void hide() {}
|
||||
public void hide()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public boolean isFocusable()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isFocusTraversable()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public Dimension minimumSize()
|
||||
{
|
||||
return getMinimumSize();
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
|
||||
public Dimension preferredSize()
|
||||
{
|
||||
return getPreferredSize();
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
|
||||
public void paint(Graphics graphics) {}
|
||||
public void paint(Graphics graphics)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public boolean prepareImage(Image img, int width, int height,
|
||||
ImageObserver o)
|
||||
{
|
||||
return comp.getToolkit().prepareImage(img, width, height, o);
|
||||
}
|
||||
|
||||
public void print(Graphics graphics) {}
|
||||
|
||||
public void repaint(long tm, int x, int y, int width, int height)
|
||||
{
|
||||
Component p = comp.getParent();
|
||||
if (p != null)
|
||||
p.repaint(tm, x + comp.getX(), y + comp.getY(), width, height);
|
||||
}
|
||||
|
||||
public void requestFocus() {}
|
||||
|
||||
public boolean requestFocus(Component source, boolean bool1, boolean bool2, long x)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reshape(int x, int y, int width, int height) {}
|
||||
public void print(Graphics graphics)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setBackground(Color color) {}
|
||||
public void repaint(long tm, int x, int y, int width, int height)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setBounds(int x, int y, int width, int height) {}
|
||||
public void requestFocus()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public boolean requestFocus(Component source, boolean bool1, boolean bool2,
|
||||
long x)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void reshape(int x, int y, int width, int height)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setBackground(Color color)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setBounds(int x, int y, int width, int height)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cursor on the heavy-weight parent peer.
|
||||
@@ -256,110 +312,141 @@ public class GLightweightPeer
|
||||
*/
|
||||
public void setCursor(Cursor cursor)
|
||||
{
|
||||
Component p = comp.getParent();
|
||||
while (p != null && p.isLightweight())
|
||||
p = p.getParent();
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
// Don't actually change the cursor of the component
|
||||
// otherwise other childs inherit this cursor.
|
||||
ComponentPeer peer = p.getPeer();
|
||||
if (peer != null)
|
||||
peer.setCursor(cursor);
|
||||
}
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {}
|
||||
|
||||
public void setEventMask(long eventMask) {}
|
||||
|
||||
public void setFont(Font font) {}
|
||||
|
||||
public void setForeground(Color color) {}
|
||||
|
||||
public void setVisible(boolean visible) {}
|
||||
|
||||
public void show() {}
|
||||
|
||||
public ColorModel getColorModel ()
|
||||
public void setEnabled(boolean enabled)
|
||||
{
|
||||
return comp.getColorModel ();
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setEventMask(long eventMask)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setFont(Font font)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setForeground(Color color)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void show()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public ColorModel getColorModel()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isObscured()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canDetermineObscurity()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void coalescePaintEvent(PaintEvent e) { }
|
||||
public void coalescePaintEvent(PaintEvent e)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void updateCursorImmediately() { }
|
||||
public void updateCursorImmediately()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public VolatileImage createVolatileImage(int width, int height)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean handlesWheelScrolling()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void createBuffers(int x, BufferCapabilities capabilities)
|
||||
throws AWTException { }
|
||||
throws AWTException
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public Image getBackBuffer()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void flip(BufferCapabilities.FlipContents contents) { }
|
||||
public void flip(BufferCapabilities.FlipContents contents)
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void destroyBuffers() { }
|
||||
public void destroyBuffers()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public boolean isRestackSupported()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void cancelPendingPaint(int x, int y, int width, int height)
|
||||
{
|
||||
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void restack()
|
||||
{
|
||||
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public Rectangle getBounds()
|
||||
{
|
||||
// Nothing to do here for lightweights.
|
||||
return null;
|
||||
}
|
||||
|
||||
public void reparent(ContainerPeer parent)
|
||||
{
|
||||
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public void setBounds(int x, int y, int z, int width, int height)
|
||||
{
|
||||
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
|
||||
public boolean isReparentSupported()
|
||||
{
|
||||
return false;
|
||||
// Nothing to do here for lightweights.
|
||||
return true;
|
||||
}
|
||||
|
||||
public void layout()
|
||||
{
|
||||
|
||||
// Nothing to do here for lightweights.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/* NativeEventLoopRunningEvent.java -- communicates to EventQueue the
|
||||
state of the native event loop
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
|
||||
public class NativeEventLoopRunningEvent
|
||||
extends AWTEvent
|
||||
{
|
||||
private boolean running;
|
||||
|
||||
public NativeEventLoopRunningEvent(Object source)
|
||||
{
|
||||
super(source, 2999);
|
||||
running = ((Boolean) source).booleanValue();
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return running;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
/* AsyncImage.java -- Loads images asynchronously
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.ImageConsumer;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Supports asynchronous loading of images.
|
||||
*/
|
||||
public class AsyncImage
|
||||
extends Image
|
||||
{
|
||||
|
||||
/**
|
||||
* Returned as source as long as the image is not complete.
|
||||
*/
|
||||
private class NullImageSource
|
||||
implements ImageProducer
|
||||
{
|
||||
private ArrayList consumers;
|
||||
|
||||
NullImageSource()
|
||||
{
|
||||
consumers = new ArrayList();
|
||||
}
|
||||
|
||||
public void addConsumer(ImageConsumer ic)
|
||||
{
|
||||
consumers.add(ic);
|
||||
}
|
||||
|
||||
public boolean isConsumer(ImageConsumer ic)
|
||||
{
|
||||
return consumers.contains(ic);
|
||||
}
|
||||
|
||||
public void removeConsumer(ImageConsumer ic)
|
||||
{
|
||||
consumers.remove(ic);
|
||||
}
|
||||
|
||||
public void requestTopDownLeftRightResend(ImageConsumer ic)
|
||||
{
|
||||
startProduction(ic);
|
||||
}
|
||||
|
||||
public void startProduction(ImageConsumer ic)
|
||||
{
|
||||
consumers.add(ic);
|
||||
for (int i = consumers.size() - 1; i >= 0; i--)
|
||||
{
|
||||
ImageConsumer c = (ImageConsumer) consumers.get(i);
|
||||
c.setDimensions(1, 1);
|
||||
ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the image asynchronously.
|
||||
*/
|
||||
private class Loader
|
||||
implements Runnable
|
||||
{
|
||||
private URL url;
|
||||
Loader(URL u)
|
||||
{
|
||||
url = u;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
Image image;
|
||||
try
|
||||
{
|
||||
GtkImage gtkImage = new GtkImage(url);
|
||||
image = CairoSurface.getBufferedImage(gtkImage);
|
||||
}
|
||||
catch (IllegalArgumentException iae)
|
||||
{
|
||||
image = null;
|
||||
}
|
||||
realImage = GtkToolkit.imageOrError(image);
|
||||
synchronized (AsyncImage.this)
|
||||
{
|
||||
notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT
|
||||
| ImageObserver.WIDTH | ImageObserver.PROPERTIES);
|
||||
observers = null; // Not needed anymore.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The real image. This is null as long as the image is not complete.
|
||||
*/
|
||||
Image realImage;
|
||||
|
||||
/**
|
||||
* The image observers.
|
||||
*
|
||||
* This is package private to avoid accessor methods.
|
||||
*/
|
||||
HashSet observers;
|
||||
|
||||
/**
|
||||
* Creates a new AsyncImage that loads from the specified URL.
|
||||
*/
|
||||
AsyncImage(URL url)
|
||||
{
|
||||
observers = new HashSet();
|
||||
Loader l = new Loader(url);
|
||||
Thread t = new Thread(l);
|
||||
t.start();
|
||||
}
|
||||
|
||||
public void flush()
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
Image r = realImage;
|
||||
Graphics g = null;
|
||||
if (r != null)
|
||||
g = r.getGraphics(); // Should we return some dummy graphics instead?
|
||||
return g;
|
||||
}
|
||||
|
||||
public int getHeight(ImageObserver observer)
|
||||
{
|
||||
addObserver(observer);
|
||||
int height = 0;
|
||||
Image r = realImage;
|
||||
if (r != null)
|
||||
height = r.getHeight(observer);
|
||||
return height;
|
||||
}
|
||||
|
||||
public Object getProperty(String name, ImageObserver observer)
|
||||
{
|
||||
addObserver(observer);
|
||||
Image r = realImage;
|
||||
Object prop = null;
|
||||
if (r != null)
|
||||
prop = r.getProperty(name, observer);
|
||||
return prop;
|
||||
}
|
||||
|
||||
public ImageProducer getSource()
|
||||
{
|
||||
Image r = realImage;
|
||||
ImageProducer source;
|
||||
if (r == null)
|
||||
source = new NullImageSource();
|
||||
else
|
||||
source = r.getSource();
|
||||
return source;
|
||||
}
|
||||
|
||||
public int getWidth(ImageObserver observer)
|
||||
{
|
||||
addObserver(observer);
|
||||
int width = 0;
|
||||
Image r = realImage;
|
||||
if (r != null)
|
||||
width = r.getWidth(observer);
|
||||
return width;
|
||||
}
|
||||
|
||||
void addObserver(ImageObserver obs)
|
||||
{
|
||||
if (obs != null)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
// This field gets null when image loading is complete and we don't
|
||||
// need to store any more observers.
|
||||
HashSet observs = observers;
|
||||
if (observs != null)
|
||||
{
|
||||
observs.add(obs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When the image is complete, notify the observer. Dunno if
|
||||
// that's really needed, but to be sure.
|
||||
obs.imageUpdate(this, ImageObserver.WIDTH
|
||||
| ImageObserver.HEIGHT
|
||||
|ImageObserver.ALLBITS
|
||||
| ImageObserver.PROPERTIES, 0, 0,
|
||||
realImage.getWidth(null),
|
||||
realImage.getHeight(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Image realImage(Image img, ImageObserver obs)
|
||||
{
|
||||
if (img instanceof AsyncImage)
|
||||
{
|
||||
((AsyncImage) img).addObserver(obs);
|
||||
Image r = ((AsyncImage) img).realImage;
|
||||
if (r != null)
|
||||
img = r;
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
void notifyObservers(int status)
|
||||
{
|
||||
assert Thread.holdsLock(this);
|
||||
// This field gets null when image loading is complete.
|
||||
HashSet observs = observers;
|
||||
if (observs != null)
|
||||
{
|
||||
Image r = realImage;
|
||||
Iterator i = observs.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
ImageObserver obs = (ImageObserver) i.next();
|
||||
obs.imageUpdate(this, status, 0, 0, r.getWidth(null),
|
||||
r.getHeight(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int checkImage(ImageObserver obs)
|
||||
{
|
||||
addObserver(obs);
|
||||
int flags = 0;
|
||||
if (realImage != null)
|
||||
flags = ImageObserver.ALLBITS | ImageObserver.WIDTH
|
||||
| ImageObserver.HEIGHT | ImageObserver.PROPERTIES;
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
@@ -38,22 +38,27 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
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.DataBuffer;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.SinglePixelPackedSampleModel;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
@@ -67,7 +72,13 @@ public class BufferedImageGraphics extends CairoGraphics2D
|
||||
/**
|
||||
* the buffered Image.
|
||||
*/
|
||||
private BufferedImage image;
|
||||
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.
|
||||
@@ -89,12 +100,6 @@ public class BufferedImageGraphics extends CairoGraphics2D
|
||||
*/
|
||||
private long cairo_t;
|
||||
|
||||
/**
|
||||
* Colormodels we recognize for fast copying.
|
||||
*/
|
||||
static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
|
||||
static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
|
||||
0xFF000000);
|
||||
private boolean hasFastCM;
|
||||
private boolean hasAlpha;
|
||||
|
||||
@@ -104,15 +109,19 @@ public class BufferedImageGraphics extends CairoGraphics2D
|
||||
this.image = bi;
|
||||
imageWidth = bi.getWidth();
|
||||
imageHeight = bi.getHeight();
|
||||
if(bi.getColorModel().equals(rgb32))
|
||||
locked = false;
|
||||
|
||||
if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel))
|
||||
hasFastCM = false;
|
||||
else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque))
|
||||
{
|
||||
hasFastCM = true;
|
||||
hasAlpha = false;
|
||||
}
|
||||
else if(bi.getColorModel().equals(argb32))
|
||||
else if(bi.getColorModel().equals(CairoSurface.cairoColorModel))
|
||||
{
|
||||
hasFastCM = true;
|
||||
hasAlpha = false;
|
||||
hasAlpha = true;
|
||||
}
|
||||
else
|
||||
hasFastCM = false;
|
||||
@@ -128,27 +137,45 @@ public class BufferedImageGraphics extends CairoGraphics2D
|
||||
|
||||
cairo_t = surface.newCairoContext();
|
||||
|
||||
DataBuffer db = bi.getRaster().getDataBuffer();
|
||||
// Get pixels out of buffered image and set in cairo surface
|
||||
Raster raster = bi.getRaster();
|
||||
int[] pixels;
|
||||
// get pixels
|
||||
|
||||
if(db instanceof CairoSurface)
|
||||
pixels = ((CairoSurface)db).getPixels(imageWidth * imageHeight);
|
||||
if (hasFastCM)
|
||||
{
|
||||
SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel();
|
||||
int minX = image.getRaster().getSampleModelTranslateX();
|
||||
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();
|
||||
|
||||
// Discard pixels that fall outside of the image's bounds
|
||||
// (ie, this image is actually a subimage of a different image)
|
||||
if (!(sm.getScanlineStride() == imageWidth && minX == 0 && minY == 0))
|
||||
{
|
||||
int[] pixels2 = new int[imageWidth * imageHeight];
|
||||
int scanline = sm.getScanlineStride();
|
||||
|
||||
for (int i = 0; i < imageHeight; i++)
|
||||
System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2, i * imageWidth, imageWidth);
|
||||
|
||||
pixels = pixels2;
|
||||
}
|
||||
|
||||
// Fill the alpha channel as opaque if image does not have alpha
|
||||
if( !hasAlpha )
|
||||
for(int i = 0; i < pixels.length; i++)
|
||||
pixels[i] &= 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( hasFastCM )
|
||||
{
|
||||
pixels = ((DataBufferInt)db).getData();
|
||||
if( !hasAlpha )
|
||||
for(int i = 0; i < pixels.length; i++)
|
||||
pixels[i] &= 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixels = CairoGraphics2D.findSimpleIntegerArray
|
||||
(image.getColorModel(),image.getData());
|
||||
}
|
||||
pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(),image.getData());
|
||||
}
|
||||
|
||||
surface.setPixels( pixels );
|
||||
|
||||
setup( cairo_t );
|
||||
@@ -157,12 +184,17 @@ public class BufferedImageGraphics extends CairoGraphics2D
|
||||
|
||||
BufferedImageGraphics(BufferedImageGraphics copyFrom)
|
||||
{
|
||||
image = copyFrom.image;
|
||||
surface = copyFrom.surface;
|
||||
cairo_t = surface.newCairoContext();
|
||||
imageWidth = copyFrom.imageWidth;
|
||||
imageHeight = copyFrom.imageHeight;
|
||||
locked = false;
|
||||
|
||||
hasFastCM = copyFrom.hasFastCM;
|
||||
hasAlpha = copyFrom.hasAlpha;
|
||||
|
||||
copy( copyFrom, cairo_t );
|
||||
setClip(0, 0, surface.width, surface.height);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,25 +202,82 @@ 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]);
|
||||
|
||||
int[] pixels = surface.getPixels(imageWidth * imageHeight);
|
||||
|
||||
if( x > imageWidth || y > imageHeight )
|
||||
return;
|
||||
|
||||
// Deal with negative width/height.
|
||||
if (height < 0)
|
||||
{
|
||||
y += height;
|
||||
height = -height;
|
||||
}
|
||||
if (width < 0)
|
||||
{
|
||||
x += width;
|
||||
width = -width;
|
||||
}
|
||||
|
||||
// Clip edges.
|
||||
if( x < 0 ){ width = width + x; x = 0; }
|
||||
if( y < 0 ){ height = height + y; y = 0; }
|
||||
if( x < 0 )
|
||||
x = 0;
|
||||
if( y < 0 )
|
||||
y = 0;
|
||||
|
||||
if( x + width > imageWidth )
|
||||
width = imageWidth - x;
|
||||
if( y + height > imageHeight )
|
||||
height = imageHeight - y;
|
||||
|
||||
if( !hasFastCM )
|
||||
image.setRGB(x, y, width, height, pixels,
|
||||
x + y * imageWidth, imageWidth);
|
||||
|
||||
if(!hasFastCM)
|
||||
{
|
||||
image.setRGB(x, y, width, height, pixels,
|
||||
x + y * imageWidth, imageWidth);
|
||||
// The setRGB method assumes (or should assume) that pixels are NOT
|
||||
// alpha-premultiplied, but Cairo stores data with premultiplication
|
||||
// (thus the pixels returned in getPixels are premultiplied).
|
||||
// This is ignored for consistency, however, since in
|
||||
// CairoGrahpics2D.drawImage we also use non-premultiplied data
|
||||
|
||||
}
|
||||
else
|
||||
System.arraycopy(pixels, y * imageWidth,
|
||||
((DataBufferInt)image.getRaster().getDataBuffer()).
|
||||
getData(), y * imageWidth, height * imageWidth);
|
||||
{
|
||||
int[] db = ((DataBufferInt)image.getRaster().getDataBuffer()).
|
||||
getData();
|
||||
|
||||
// This should not fail, as we check the image sample model when we
|
||||
// set the hasFastCM flag
|
||||
SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel() ;
|
||||
|
||||
int minX = image.getRaster().getSampleModelTranslateX();
|
||||
int minY = image.getRaster().getSampleModelTranslateY();
|
||||
|
||||
if (sm.getScanlineStride() == imageWidth && minX == 0)
|
||||
{
|
||||
System.arraycopy(pixels, y * imageWidth,
|
||||
db, (y - minY) * imageWidth,
|
||||
height * imageWidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
int scanline = sm.getScanlineStride();
|
||||
for (int i = y; i < (height + y); i++)
|
||||
System.arraycopy(pixels, i * imageWidth + x, db,
|
||||
(i - minY) * scanline + x - minX, width);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,36 +310,246 @@ public class BufferedImageGraphics extends CairoGraphics2D
|
||||
*/
|
||||
public void draw(Shape s)
|
||||
{
|
||||
super.draw(s);
|
||||
Rectangle r = s.getBounds();
|
||||
updateBufferedImage(r.x, r.y, r.width, r.height);
|
||||
// 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);
|
||||
updateBufferedImage(r.x, r.y, r.width, r.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setStroke(this.getStroke());
|
||||
g2d.setColor(this.getColor());
|
||||
g2d.setTransform(transform);
|
||||
g2d.draw(s);
|
||||
|
||||
drawComposite(r.getBounds2D(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(Shape s)
|
||||
{
|
||||
super.fill(s);
|
||||
Rectangle r = s.getBounds();
|
||||
updateBufferedImage(r.x, r.y, r.width, r.height);
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
{
|
||||
super.fill(s);
|
||||
Rectangle r = s.getBounds();
|
||||
updateBufferedImage(r.x, r.y, r.width, r.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setPaint(this.getPaint());
|
||||
g2d.setColor(this.getColor());
|
||||
g2d.setTransform(transform);
|
||||
g2d.fill(s);
|
||||
|
||||
drawComposite(s.getBounds2D(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRenderedImage(RenderedImage image, AffineTransform xform)
|
||||
{
|
||||
super.drawRenderedImage(image, xform);
|
||||
updateBufferedImage(0, 0, imageWidth, imageHeight);
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
{
|
||||
super.drawRenderedImage(image, xform);
|
||||
updateBufferedImage(0, 0, imageWidth, imageHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setRenderingHints(this.getRenderingHints());
|
||||
g2d.setTransform(transform);
|
||||
g2d.drawRenderedImage(image, xform);
|
||||
|
||||
drawComposite(buffer.getRaster().getBounds(), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean drawImage(Image img, AffineTransform xform,
|
||||
Color bgcolor, ImageObserver obs)
|
||||
{
|
||||
boolean rv = super.drawImage(img, xform, bgcolor, obs);
|
||||
updateBufferedImage(0, 0, imageWidth, imageHeight);
|
||||
return rv;
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
{
|
||||
boolean rv = super.drawImage(img, xform, bgcolor, obs);
|
||||
updateBufferedImage(0, 0, imageWidth, imageHeight);
|
||||
return rv;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get buffered image of source
|
||||
if( !(img instanceof BufferedImage) )
|
||||
{
|
||||
ImageProducer source = img.getSource();
|
||||
if (source == null)
|
||||
return false;
|
||||
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(),
|
||||
bImg.getHeight() + bImg.getMinY());
|
||||
if (xform != null)
|
||||
{
|
||||
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
|
||||
return drawComposite(new Rectangle2D.Double(origin.getX(),
|
||||
origin.getY(),
|
||||
pt.getX(), pt.getY()),
|
||||
obs);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawGlyphVector(GlyphVector gv, float x, float y)
|
||||
{
|
||||
super.drawGlyphVector(gv, x, y);
|
||||
updateBufferedImage(0, 0, imageWidth, imageHeight);
|
||||
// Find absolute bounds, in user-space, of this glyph vector
|
||||
Rectangle2D bounds = gv.getLogicalBounds();
|
||||
bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
|
||||
bounds.getWidth(), bounds.getHeight());
|
||||
|
||||
// Perform draw operation
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
{
|
||||
super.drawGlyphVector(gv, x, y);
|
||||
updateBufferedImage((int)bounds.getX(), (int)bounds.getY(),
|
||||
(int)bounds.getWidth(), (int)bounds.getHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setPaint(this.getPaint());
|
||||
g2d.setStroke(this.getStroke());
|
||||
g2d.setTransform(transform);
|
||||
g2d.drawGlyphVector(gv, x, y);
|
||||
|
||||
drawComposite(bounds, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform composite drawing from the buffer onto the main image.
|
||||
*
|
||||
* The image to be composited should already be drawn into the buffer, in the
|
||||
* proper place, after all necessary transforms have been applied.
|
||||
*
|
||||
* @param bounds The bounds to draw, in user-space.
|
||||
* @param observer The image observer, if any (may be null).
|
||||
* @return True on success, false on failure.
|
||||
*/
|
||||
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]));
|
||||
|
||||
// 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 conservative 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));
|
||||
|
||||
// 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());
|
||||
|
||||
// Find subimage of main image for updating
|
||||
BufferedImage current = image;
|
||||
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(),
|
||||
current.getRaster());
|
||||
|
||||
// Prevent the clearRect in CairoGraphics2D.drawImage from clearing
|
||||
// our composited image
|
||||
locked = true;
|
||||
|
||||
// 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(current,
|
||||
AffineTransform.getTranslateInstance(bounds.getX(),
|
||||
bounds.getY()),
|
||||
new Color(0,0,0,0), null);
|
||||
locked = false;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
buffer = new BufferedImage(image.getWidth(), image.getHeight(),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
|
||||
|
||||
g2d.setBackground(new Color(0,0,0,0));
|
||||
g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
protected ColorModel getNativeCM()
|
||||
{
|
||||
return image.getColorModel();
|
||||
}
|
||||
|
||||
protected ColorModel getBufferCM()
|
||||
{
|
||||
return ColorModel.getRGBdefault();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.CompositeContext;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.GradientPaint;
|
||||
@@ -53,6 +54,8 @@ import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.PaintContext;
|
||||
import java.awt.Point;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
@@ -68,6 +71,7 @@ import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Area;
|
||||
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.Point2D;
|
||||
@@ -131,6 +135,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
* The current paint
|
||||
*/
|
||||
Paint paint;
|
||||
boolean customPaint;
|
||||
|
||||
/**
|
||||
* The current stroke
|
||||
@@ -161,6 +166,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
* The current compositing context, if any.
|
||||
*/
|
||||
Composite comp;
|
||||
CompositeContext compCtx;
|
||||
|
||||
/**
|
||||
* Rendering hint map.
|
||||
@@ -172,7 +178,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
* coords be shifted to land on 0.5-pixel boundaries, in order to land on
|
||||
* "middle of pixel" coordinates and light up complete pixels.
|
||||
*/
|
||||
private boolean shiftDrawCalls = false;
|
||||
protected boolean shiftDrawCalls = false;
|
||||
|
||||
/**
|
||||
* Keep track if the first clip to be set, which is restored on setClip(null);
|
||||
@@ -189,6 +195,18 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
|
||||
0xFF000000);
|
||||
|
||||
/**
|
||||
* Native constants for interpolation methods.
|
||||
* Note, this corresponds to an enum in native/jni/gtk-peer/cairographics2d.h
|
||||
*/
|
||||
public static final int INTERPOLATION_NEAREST = 0,
|
||||
INTERPOLATION_BILINEAR = 1,
|
||||
INTERPOLATION_BICUBIC = 5,
|
||||
ALPHA_INTERPOLATION_SPEED = 2,
|
||||
ALPHA_INTERPOLATION_QUALITY = 3,
|
||||
ALPHA_INTERPOLATION_DEFAULT = 4;
|
||||
// TODO: Does ALPHA_INTERPOLATION really correspond to CAIRO_FILTER_FAST/BEST/GOOD?
|
||||
|
||||
/**
|
||||
* Constructor does nothing.
|
||||
*/
|
||||
@@ -204,7 +222,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
nativePointer = init(cairo_t_pointer);
|
||||
setRenderingHints(new RenderingHints(getDefaultHints()));
|
||||
font = new Font("SansSerif", Font.PLAIN, 12);
|
||||
setFont(new Font("SansSerif", Font.PLAIN, 12));
|
||||
setColor(Color.black);
|
||||
setBackground(Color.white);
|
||||
setPaint(Color.black);
|
||||
@@ -239,6 +257,8 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
bg = new Color(g.bg.getRGB());
|
||||
}
|
||||
|
||||
firstClip = g.firstClip;
|
||||
originalClip = g.originalClip;
|
||||
clip = g.getClip();
|
||||
|
||||
if (g.transform == null)
|
||||
@@ -246,14 +266,14 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
else
|
||||
transform = new AffineTransform(g.transform);
|
||||
|
||||
font = g.font;
|
||||
|
||||
setFont(g.font);
|
||||
setColor(foreground);
|
||||
setBackground(bg);
|
||||
setPaint(paint);
|
||||
setStroke(stroke);
|
||||
setTransformImpl(transform);
|
||||
setClip(clip);
|
||||
setComposite(comp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,6 +294,8 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
disposeNative(nativePointer);
|
||||
nativePointer = 0;
|
||||
if (compCtx != null)
|
||||
compCtx.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,6 +315,11 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
int width, int height, int dx, int dy);
|
||||
|
||||
|
||||
/**
|
||||
* Find the bounds of this graphics context, in device space.
|
||||
*
|
||||
* @return the bounds in device-space
|
||||
*/
|
||||
protected abstract Rectangle2D getRealBounds();
|
||||
|
||||
////// Native Methods ////////////////////////////////////////////////////
|
||||
@@ -309,15 +336,17 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
* @param i2u - affine transform array
|
||||
*/
|
||||
private native void drawPixels(long pointer, int[] pixels, int w, int h,
|
||||
int stride, double[] i2u, double alpha);
|
||||
int stride, double[] i2u, double alpha,
|
||||
int interpolation);
|
||||
|
||||
private native void setGradient(long pointer, double x1, double y1,
|
||||
double x2, double y2,
|
||||
int r1, int g1, int b1, int a1, int r2,
|
||||
int g2, int b2, int a2, boolean cyclic);
|
||||
|
||||
private native void setTexturePixels(long pointer, int[] pixels, int w,
|
||||
int h, int stride);
|
||||
private native void setPaintPixels(long pointer, int[] pixels, int w,
|
||||
int h, int stride, boolean repeat,
|
||||
int x, int y);
|
||||
|
||||
/**
|
||||
* Set the current transform matrix
|
||||
@@ -365,6 +394,10 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
float x, float y, int n,
|
||||
int[] codes, float[] positions);
|
||||
|
||||
/**
|
||||
* Set the font in cairo.
|
||||
*/
|
||||
private native void cairoSetFont(long pointer, GdkFontPeer font);
|
||||
|
||||
private native void cairoRelCurveTo(long pointer, double dx1, double dy1,
|
||||
double dx2, double dy2, double dx3,
|
||||
@@ -440,11 +473,6 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
*/
|
||||
private native void cairoResetClip(long pointer);
|
||||
|
||||
/**
|
||||
* Set interpolation types
|
||||
*/
|
||||
private native void cairoSurfaceSetFilter(long pointer, int filter);
|
||||
|
||||
/**
|
||||
* Draws a line from (x1,y1) to (x2,y2).
|
||||
*
|
||||
@@ -666,13 +694,14 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
|
||||
public void setPaint(Paint p)
|
||||
{
|
||||
if (paint == null)
|
||||
if (p == null)
|
||||
return;
|
||||
|
||||
paint = p;
|
||||
if (paint instanceof Color)
|
||||
{
|
||||
setColor((Color) paint);
|
||||
customPaint = false;
|
||||
}
|
||||
else if (paint instanceof TexturePaint)
|
||||
{
|
||||
@@ -690,7 +719,8 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
|
||||
BufferedImage texture = op.filter(img, null);
|
||||
int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
|
||||
setTexturePixels(nativePointer, pixels, width, height, width);
|
||||
setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0);
|
||||
customPaint = false;
|
||||
}
|
||||
else if (paint instanceof GradientPaint)
|
||||
{
|
||||
@@ -703,9 +733,108 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(),
|
||||
c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(),
|
||||
gp.isCyclic());
|
||||
customPaint = false;
|
||||
}
|
||||
else
|
||||
throw new java.lang.UnsupportedOperationException();
|
||||
{
|
||||
customPaint = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom paint
|
||||
*
|
||||
* @param bounds the bounding box, in user space
|
||||
*/
|
||||
protected void setCustomPaint(Rectangle bounds)
|
||||
{
|
||||
if (paint instanceof Color || paint instanceof TexturePaint
|
||||
|| paint instanceof GradientPaint)
|
||||
return;
|
||||
|
||||
int userX = bounds.x;
|
||||
int userY = bounds.y;
|
||||
int userWidth = bounds.width;
|
||||
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());
|
||||
|
||||
// Get raster of the paint background
|
||||
PaintContext pc = paint.createContext(CairoSurface.cairoColorModel,
|
||||
new Rectangle(deviceX, deviceY,
|
||||
deviceWidth,
|
||||
deviceHeight),
|
||||
bounds,
|
||||
transform, hints);
|
||||
|
||||
Raster raster = pc.getRaster(deviceX, deviceY, deviceWidth,
|
||||
deviceHeight);
|
||||
|
||||
// Clear the transform matrix in Cairo, since the raster returned by the
|
||||
// PaintContext is already in device-space
|
||||
AffineTransform oldTx = new AffineTransform(transform);
|
||||
setTransformImpl(new AffineTransform());
|
||||
|
||||
// Set pixels in cairo, aligning the top-left of the background image
|
||||
// to the top-left corner in device space
|
||||
if (pc.getColorModel().equals(CairoSurface.cairoColorModel)
|
||||
&& raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT)
|
||||
{
|
||||
// Use a fast copy if the paint context can uses a Cairo-compatible
|
||||
// color model
|
||||
setPaintPixels(nativePointer,
|
||||
(int[])raster.getDataElements(0, 0, deviceWidth,
|
||||
deviceHeight, null),
|
||||
deviceWidth, deviceHeight, deviceWidth, false,
|
||||
deviceX, deviceY);
|
||||
}
|
||||
|
||||
else if (pc.getColorModel().equals(CairoSurface.cairoCM_opaque)
|
||||
&& raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT)
|
||||
{
|
||||
// We can also optimize if the context uses a similar color model
|
||||
// but without an alpha channel; we just add the alpha
|
||||
int[] pixels = (int[])raster.getDataElements(0, 0, deviceWidth,
|
||||
deviceHeight, null);
|
||||
|
||||
for (int i = 0; i < pixels.length; i++)
|
||||
pixels[i] = 0xff000000 | (pixels[i] & 0x00ffffff);
|
||||
|
||||
setPaintPixels(nativePointer, pixels, deviceWidth, deviceHeight,
|
||||
deviceWidth, false, deviceX, deviceY);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Fall back on wrapping the raster in a BufferedImage, and
|
||||
// use BufferedImage.getRGB() to do color-model conversion
|
||||
WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(),
|
||||
new Point(raster.getMinX(),
|
||||
raster.getMinY()));
|
||||
wr.setRect(raster);
|
||||
|
||||
BufferedImage img2 = new BufferedImage(pc.getColorModel(), wr,
|
||||
pc.getColorModel().isAlphaPremultiplied(),
|
||||
null);
|
||||
|
||||
setPaintPixels(nativePointer,
|
||||
img2.getRGB(0, 0, deviceWidth, deviceHeight, null, 0,
|
||||
deviceWidth),
|
||||
deviceWidth, deviceHeight, deviceWidth, false,
|
||||
deviceX, deviceY);
|
||||
}
|
||||
|
||||
// Restore transform
|
||||
setTransformImpl(oldTx);
|
||||
}
|
||||
|
||||
public Stroke getStroke()
|
||||
@@ -736,6 +865,33 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to find the bounds of a shape, including the stroke width.
|
||||
*
|
||||
* @param s the shape
|
||||
* @return the bounds of the shape, including stroke width
|
||||
*/
|
||||
protected Rectangle findStrokedBounds(Shape s)
|
||||
{
|
||||
Rectangle r = s.getBounds();
|
||||
|
||||
if (stroke instanceof BasicStroke)
|
||||
{
|
||||
int strokeWidth = (int)Math.ceil(((BasicStroke)stroke).getLineWidth());
|
||||
r.x -= strokeWidth / 2;
|
||||
r.y -= strokeWidth / 2;
|
||||
r.height += strokeWidth;
|
||||
r.width += strokeWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
Shape s2 = stroke.createStrokedShape(s);
|
||||
r = s2.getBounds();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public void setPaintMode()
|
||||
{
|
||||
setComposite(AlphaComposite.SrcOver);
|
||||
@@ -896,25 +1052,56 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
*/
|
||||
public void setComposite(Composite comp)
|
||||
{
|
||||
if (this.comp == comp)
|
||||
return;
|
||||
|
||||
this.comp = comp;
|
||||
if (compCtx != null)
|
||||
compCtx.dispose();
|
||||
compCtx = null;
|
||||
|
||||
if (comp instanceof AlphaComposite)
|
||||
{
|
||||
AlphaComposite a = (AlphaComposite) comp;
|
||||
cairoSetOperator(nativePointer, a.getRule());
|
||||
cairoSetOperator(nativePointer, a.getRule());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// FIXME: this check is only required "if this Graphics2D
|
||||
// context is drawing to a Component on the display screen".
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkPermission(new AWTPermission("readDisplayPixels"));
|
||||
|
||||
// FIXME: implement general Composite support
|
||||
throw new java.lang.UnsupportedOperationException();
|
||||
cairoSetOperator(nativePointer, AlphaComposite.SRC_OVER);
|
||||
|
||||
if (comp != null)
|
||||
{
|
||||
// FIXME: this check is only required "if this Graphics2D
|
||||
// context is drawing to a Component on the display screen".
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkPermission(new AWTPermission("readDisplayPixels"));
|
||||
|
||||
compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Colour Model describing the native, raw image data for this
|
||||
* specific peer.
|
||||
*
|
||||
* @return ColorModel the ColorModel of native data in this peer
|
||||
*/
|
||||
protected abstract ColorModel getNativeCM();
|
||||
|
||||
/**
|
||||
* Returns the Color Model describing the buffer that this peer uses
|
||||
* for custom composites.
|
||||
*
|
||||
* @return ColorModel the ColorModel of the composite buffer in this peer.
|
||||
*/
|
||||
protected ColorModel getBufferCM()
|
||||
{
|
||||
// This may be overridden by some subclasses
|
||||
return getNativeCM();
|
||||
}
|
||||
|
||||
///////////////////////// DRAWING PRIMITIVES ///////////////////////////////////
|
||||
|
||||
@@ -929,21 +1116,30 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
return;
|
||||
}
|
||||
|
||||
createPath(s);
|
||||
if (customPaint)
|
||||
{
|
||||
Rectangle r = findStrokedBounds(s);
|
||||
setCustomPaint(r);
|
||||
}
|
||||
|
||||
createPath(s, true);
|
||||
cairoStroke(nativePointer);
|
||||
}
|
||||
|
||||
public void fill(Shape s)
|
||||
{
|
||||
createPath(s);
|
||||
createPath(s, false);
|
||||
|
||||
if (customPaint)
|
||||
setCustomPaint(s.getBounds());
|
||||
|
||||
double alpha = 1.0;
|
||||
if (comp instanceof AlphaComposite)
|
||||
alpha = ((AlphaComposite) comp).getAlpha();
|
||||
cairoFill(nativePointer, alpha);
|
||||
}
|
||||
|
||||
private void createPath(Shape s)
|
||||
private void createPath(Shape s, boolean isDraw)
|
||||
{
|
||||
cairoNewPath(nativePointer);
|
||||
|
||||
@@ -951,9 +1147,25 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
if (s instanceof Rectangle2D)
|
||||
{
|
||||
Rectangle2D r = (Rectangle2D) s;
|
||||
cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls),
|
||||
shifted(r.getY(), shiftDrawCalls), r.getWidth(),
|
||||
r.getHeight());
|
||||
|
||||
// Pixels need to be shifted in draw operations to ensure that they
|
||||
// light up entire pixels, but we also need to make sure the rectangle
|
||||
// does not get distorted by this shifting operation
|
||||
double x = shiftX(r.getX(),shiftDrawCalls && isDraw);
|
||||
double y = shiftY(r.getY(), shiftDrawCalls && isDraw);
|
||||
double w = Math.round(r.getWidth());
|
||||
double h = Math.round(r.getHeight());
|
||||
cairoRectangle(nativePointer, x, y, w, h);
|
||||
}
|
||||
|
||||
// Lines are easy too
|
||||
else if (s instanceof Line2D)
|
||||
{
|
||||
Line2D l = (Line2D) s;
|
||||
cairoMoveTo(nativePointer, shiftX(l.getX1(), shiftDrawCalls && isDraw),
|
||||
shiftY(l.getY1(), shiftDrawCalls && isDraw));
|
||||
cairoLineTo(nativePointer, shiftX(l.getX2(), shiftDrawCalls && isDraw),
|
||||
shiftY(l.getY2(), shiftDrawCalls && isDraw));
|
||||
}
|
||||
|
||||
// We can optimize ellipses too; however we don't bother optimizing arcs:
|
||||
@@ -982,9 +1194,9 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
}
|
||||
|
||||
cairoArc(nativePointer,
|
||||
shifted(e.getCenterX() / xscale, shiftDrawCalls),
|
||||
shifted(e.getCenterY() / yscale, shiftDrawCalls), radius, 0,
|
||||
Math.PI * 2);
|
||||
shiftX(e.getCenterX() / xscale, shiftDrawCalls && isDraw),
|
||||
shiftY(e.getCenterY() / yscale, shiftDrawCalls && isDraw),
|
||||
radius, 0, Math.PI * 2);
|
||||
|
||||
if (xscale != 1 || yscale != 1)
|
||||
cairoRestore(nativePointer);
|
||||
@@ -993,7 +1205,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
// All other shapes are broken down and drawn in steps using the
|
||||
// PathIterator
|
||||
else
|
||||
walkPath(s.getPathIterator(null), shiftDrawCalls);
|
||||
walkPath(s.getPathIterator(null), shiftDrawCalls && isDraw);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1006,8 +1218,14 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
if (bg != null)
|
||||
cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0,
|
||||
bg.getGreen() / 255.0, bg.getBlue() / 255.0, 1.0);
|
||||
bg.getGreen() / 255.0, bg.getBlue() / 255.0,
|
||||
bg.getAlpha() / 255.0);
|
||||
|
||||
Composite oldcomp = comp;
|
||||
setComposite(AlphaComposite.Src);
|
||||
fillRect(x, y, width, height);
|
||||
|
||||
setComposite(oldcomp);
|
||||
updateColor();
|
||||
}
|
||||
|
||||
@@ -1033,15 +1251,14 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
// to draw a single pixel. This is emulated by drawing
|
||||
// a one pixel sized rectangle.
|
||||
if (x1 == x2 && y1 == y2)
|
||||
cairoFillRect(nativePointer, x1, y1, 1, 1);
|
||||
fill(new Rectangle(x1, y1, 1, 1));
|
||||
else
|
||||
cairoDrawLine(nativePointer, x1 + 0.5, y1 + 0.5, x2 + 0.5, y2 + 0.5);
|
||||
draw(new Line2D.Double(x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
public void drawRect(int x, int y, int width, int height)
|
||||
{
|
||||
cairoDrawRect(nativePointer, shifted(x, shiftDrawCalls),
|
||||
shifted(y, shiftDrawCalls), width, height);
|
||||
draw(new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
public void fillArc(int x, int y, int width, int height, int startAngle,
|
||||
@@ -1049,12 +1266,12 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
fill(new Arc2D.Double((double) x, (double) y, (double) width,
|
||||
(double) height, (double) startAngle,
|
||||
(double) arcAngle, Arc2D.OPEN));
|
||||
(double) arcAngle, Arc2D.PIE));
|
||||
}
|
||||
|
||||
public void fillRect(int x, int y, int width, int height)
|
||||
{
|
||||
cairoFillRect(nativePointer, x, y, width, height);
|
||||
fill (new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
|
||||
@@ -1117,7 +1334,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
|
||||
Rectangle2D r = getRealBounds();
|
||||
|
||||
if( width < 0 || height < 0 )
|
||||
if( width <= 0 || height <= 0 )
|
||||
return;
|
||||
// Return if outside the surface
|
||||
if( x + dx > r.getWidth() || y + dy > r.getHeight() )
|
||||
@@ -1150,32 +1367,10 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
|
||||
///////////////////////// RENDERING HINTS ///////////////////////////////////
|
||||
|
||||
/**
|
||||
* FIXME- support better
|
||||
*/
|
||||
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
|
||||
{
|
||||
hints.put(hintKey, hintValue);
|
||||
|
||||
if (hintKey.equals(RenderingHints.KEY_INTERPOLATION)
|
||||
|| hintKey.equals(RenderingHints.KEY_ALPHA_INTERPOLATION))
|
||||
{
|
||||
if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
|
||||
cairoSurfaceSetFilter(nativePointer, 0);
|
||||
|
||||
else if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
cairoSurfaceSetFilter(nativePointer, 1);
|
||||
|
||||
else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
|
||||
cairoSurfaceSetFilter(nativePointer, 2);
|
||||
|
||||
else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
|
||||
cairoSurfaceSetFilter(nativePointer, 3);
|
||||
|
||||
else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
|
||||
cairoSurfaceSetFilter(nativePointer, 4);
|
||||
}
|
||||
|
||||
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|
||||
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
|
||||
}
|
||||
@@ -1189,30 +1384,15 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
this.hints = new RenderingHints(getDefaultHints());
|
||||
this.hints.add(new RenderingHints(hints));
|
||||
|
||||
if (hints.containsKey(RenderingHints.KEY_INTERPOLATION))
|
||||
{
|
||||
if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
|
||||
cairoSurfaceSetFilter(nativePointer, 0);
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
cairoSurfaceSetFilter(nativePointer, 1);
|
||||
}
|
||||
|
||||
if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION))
|
||||
{
|
||||
if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
|
||||
cairoSurfaceSetFilter(nativePointer, 2);
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
|
||||
cairoSurfaceSetFilter(nativePointer, 3);
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
|
||||
cairoSurfaceSetFilter(nativePointer, 4);
|
||||
}
|
||||
|
||||
|
||||
shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
|
||||
|| hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
|
||||
|
||||
if (compCtx != null)
|
||||
{
|
||||
compCtx.dispose();
|
||||
compCtx = comp.createContext(getNativeCM(), getNativeCM(), this.hints);
|
||||
}
|
||||
}
|
||||
|
||||
public void addRenderingHints(Map hints)
|
||||
@@ -1224,6 +1404,30 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
return hints;
|
||||
}
|
||||
|
||||
private int getInterpolation()
|
||||
{
|
||||
if (this.hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
|
||||
return INTERPOLATION_NEAREST;
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
|
||||
return INTERPOLATION_BILINEAR;
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC))
|
||||
return INTERPOLATION_BICUBIC;
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
|
||||
return ALPHA_INTERPOLATION_SPEED;
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
|
||||
return ALPHA_INTERPOLATION_QUALITY;
|
||||
|
||||
else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
|
||||
return ALPHA_INTERPOLATION_DEFAULT;
|
||||
|
||||
// Do bilinear interpolation as default
|
||||
return INTERPOLATION_BILINEAR;
|
||||
}
|
||||
|
||||
///////////////////////// IMAGE. METHODS ///////////////////////////////////
|
||||
|
||||
@@ -1259,7 +1463,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
// Note - this can get us in trouble when the gdk lock is re-acquired.
|
||||
// for example by VolatileImage. See ComponentGraphics for how we work
|
||||
// around this.
|
||||
|
||||
img = AsyncImage.realImage(img, obs);
|
||||
if( !(img instanceof BufferedImage) )
|
||||
{
|
||||
ImageProducer source = img.getSource();
|
||||
@@ -1269,18 +1473,18 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
}
|
||||
|
||||
BufferedImage b = (BufferedImage) img;
|
||||
DataBuffer db;
|
||||
Raster raster;
|
||||
double[] i2u = new double[6];
|
||||
int width = b.getWidth();
|
||||
int height = b.getHeight();
|
||||
|
||||
|
||||
// If this BufferedImage has a BufferedImageGraphics object,
|
||||
// use the cached CairoSurface that BIG is drawing onto
|
||||
|
||||
if( BufferedImageGraphics.bufferedImages.get( b ) != null )
|
||||
db = (DataBuffer)BufferedImageGraphics.bufferedImages.get( b );
|
||||
raster = (Raster)BufferedImageGraphics.bufferedImages.get( b );
|
||||
else
|
||||
db = b.getRaster().getDataBuffer();
|
||||
raster = b.getRaster();
|
||||
|
||||
invertedXform.getMatrix(i2u);
|
||||
|
||||
@@ -1288,29 +1492,37 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
if (comp instanceof AlphaComposite)
|
||||
alpha = ((AlphaComposite) comp).getAlpha();
|
||||
|
||||
if(db instanceof CairoSurface)
|
||||
if(raster instanceof CairoSurface)
|
||||
{
|
||||
((CairoSurface)db).drawSurface(nativePointer, i2u, alpha);
|
||||
((CairoSurface)raster).drawSurface(nativePointer, i2u, alpha,
|
||||
getInterpolation());
|
||||
updateColor();
|
||||
return true;
|
||||
}
|
||||
|
||||
if( bgcolor != null )
|
||||
{
|
||||
// Fill a rectangle with the background color
|
||||
// to composite the image onto.
|
||||
Paint oldPaint = paint;
|
||||
AffineTransform oldTransform = transform;
|
||||
setPaint( bgcolor );
|
||||
setTransform( invertedXform );
|
||||
fillRect(0, 0, width, height);
|
||||
setTransform( oldTransform );
|
||||
setPaint( oldPaint );
|
||||
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]);
|
||||
|
||||
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.
|
||||
|
||||
drawPixels(nativePointer, pixels, width, height, width, i2u, alpha);
|
||||
drawPixels(nativePointer, pixels, width, height, width, i2u, alpha,
|
||||
getInterpolation());
|
||||
|
||||
// Cairo seems to lose the current color which must be restored.
|
||||
updateColor();
|
||||
@@ -1428,8 +1640,14 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
{
|
||||
if (str == null || str.length() == 0)
|
||||
return;
|
||||
(new TextLayout( str, getFont(), getFontRenderContext() )).
|
||||
draw(this, x, y);
|
||||
GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
|
||||
TextLayout tl = (TextLayout) fontPeer.textLayoutCache.get(str);
|
||||
if (tl == null)
|
||||
{
|
||||
tl = new TextLayout( str, getFont(), getFontRenderContext() );
|
||||
fontPeer.textLayoutCache.put(str, tl);
|
||||
}
|
||||
tl.draw(this, x, y);
|
||||
}
|
||||
|
||||
public void drawString(String str, int x, int y)
|
||||
@@ -1449,6 +1667,9 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
if( gv.getNumGlyphs() <= 0 )
|
||||
return;
|
||||
|
||||
if (customPaint)
|
||||
setCustomPaint(gv.getOutline().getBounds());
|
||||
|
||||
if (comp instanceof AlphaComposite)
|
||||
alpha = ((AlphaComposite) comp).getAlpha();
|
||||
if (gv instanceof FreetypeGlyphVector && alpha == 1.0)
|
||||
@@ -1458,9 +1679,10 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
float[] positions = gv.getGlyphPositions (0, n, null);
|
||||
|
||||
setFont (gv.getFont ());
|
||||
synchronized( this.font )
|
||||
GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
|
||||
synchronized (fontPeer)
|
||||
{
|
||||
cairoDrawGlyphVector(nativePointer, (GdkFontPeer)getFont().getPeer(),
|
||||
cairoDrawGlyphVector(nativePointer, fontPeer,
|
||||
x, y, n, codes, positions);
|
||||
}
|
||||
}
|
||||
@@ -1498,9 +1720,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
|
||||
public FontMetrics getFontMetrics(Font f)
|
||||
{
|
||||
// the reason we go via the toolkit here is to try to get
|
||||
// a cached object. the toolkit keeps such a cache.
|
||||
return Toolkit.getDefaultToolkit().getFontMetrics(f);
|
||||
return ((GdkFontPeer) f.getPeer()).getFontMetrics(f);
|
||||
}
|
||||
|
||||
public void setFont(Font f)
|
||||
@@ -1516,6 +1736,12 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
font =
|
||||
((ClasspathToolkit)(Toolkit.getDefaultToolkit()))
|
||||
.getFont(f.getName(), f.getAttributes());
|
||||
|
||||
GdkFontPeer fontpeer = (GdkFontPeer) getFont().getPeer();
|
||||
synchronized (fontpeer)
|
||||
{
|
||||
cairoSetFont(nativePointer, fontpeer);
|
||||
}
|
||||
}
|
||||
|
||||
public Font getFont()
|
||||
@@ -1626,7 +1852,7 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
if (comp instanceof AlphaComposite)
|
||||
alpha = ((AlphaComposite) comp).getAlpha();
|
||||
drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(),
|
||||
r.getWidth(), i2u, alpha);
|
||||
r.getWidth(), i2u, alpha, getInterpolation());
|
||||
|
||||
// Cairo seems to lose the current color which must be restored.
|
||||
updateColor();
|
||||
@@ -1635,12 +1861,33 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts coordinates by 0.5.
|
||||
* Shifts an x-coordinate by 0.5 in device space.
|
||||
*/
|
||||
private double shifted(double coord, boolean doShift)
|
||||
private double shiftX(double coord, boolean doShift)
|
||||
{
|
||||
if (doShift)
|
||||
return Math.floor(coord) + 0.5;
|
||||
{
|
||||
double shift = 0.5;
|
||||
if (!transform.isIdentity())
|
||||
shift /= transform.getScaleX();
|
||||
return Math.round(coord) + shift;
|
||||
}
|
||||
else
|
||||
return coord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts a y-coordinate by 0.5 in device space.
|
||||
*/
|
||||
private double shiftY(double coord, boolean doShift)
|
||||
{
|
||||
if (doShift)
|
||||
{
|
||||
double shift = 0.5;
|
||||
if (!transform.isIdentity())
|
||||
shift /= transform.getScaleY();
|
||||
return Math.round(coord) + shift;
|
||||
}
|
||||
else
|
||||
return coord;
|
||||
}
|
||||
@@ -1661,35 +1908,35 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
switch (seg)
|
||||
{
|
||||
case PathIterator.SEG_MOVETO:
|
||||
x = shifted(coords[0], doShift);
|
||||
y = shifted(coords[1], doShift);
|
||||
x = shiftX(coords[0], doShift);
|
||||
y = shiftY(coords[1], doShift);
|
||||
cairoMoveTo(nativePointer, x, y);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
x = shifted(coords[0], doShift);
|
||||
y = shifted(coords[1], doShift);
|
||||
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) * (shifted(coords[0], doShift) - x);
|
||||
double y1 = y + (2.0 / 3.0) * (shifted(coords[1], doShift) - y);
|
||||
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) * (shifted(coords[2], doShift) - x);
|
||||
double y2 = y1 + (1.0 / 3.0) * (shifted(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 = shifted(coords[2], doShift);
|
||||
y = shifted(coords[3], doShift);
|
||||
x = shiftX(coords[2], doShift);
|
||||
y = shiftY(coords[3], doShift);
|
||||
cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
x = shifted(coords[4], doShift);
|
||||
y = shifted(coords[5], doShift);
|
||||
cairoCurveTo(nativePointer, shifted(coords[0], doShift),
|
||||
shifted(coords[1], doShift),
|
||||
shifted(coords[2], doShift),
|
||||
shifted(coords[3], doShift), x, y);
|
||||
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);
|
||||
@@ -1807,4 +2054,4 @@ public abstract class CairoGraphics2D extends Graphics2D
|
||||
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,14 +38,18 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import java.awt.Point;
|
||||
import gnu.java.awt.Buffers;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.awt.Point;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.SinglePixelPackedSampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Hashtable;
|
||||
|
||||
@@ -54,7 +58,7 @@ import java.util.Hashtable;
|
||||
*
|
||||
* @author Sven de Marothy
|
||||
*/
|
||||
public class CairoSurface extends DataBuffer
|
||||
public class CairoSurface extends WritableRaster
|
||||
{
|
||||
int width = -1, height = -1;
|
||||
|
||||
@@ -68,13 +72,27 @@ public class CairoSurface extends DataBuffer
|
||||
*/
|
||||
long bufferPointer;
|
||||
|
||||
// FIXME: use only the cairoCM_pre colormodel
|
||||
// since that's what Cairo really uses (is there a way to do this cheaply?
|
||||
// we use a non-multiplied model most of the time to avoid costly coercion
|
||||
// operations...)
|
||||
static ColorModel cairoColorModel = new DirectColorModel(32, 0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000);
|
||||
|
||||
static ColorModel nativeModel = new DirectColorModel(32,
|
||||
0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000);
|
||||
|
||||
static ColorModel cairoCM_pre = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||
32, 0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF,
|
||||
0xFF000000,
|
||||
true,
|
||||
Buffers.smallestAppropriateTransferType(32));
|
||||
|
||||
// This CM corresponds to the CAIRO_FORMAT_RGB24 type in Cairo
|
||||
static ColorModel cairoCM_opaque = new DirectColorModel(24, 0x00FF0000,
|
||||
0x0000FF00,
|
||||
0x000000FF);
|
||||
/**
|
||||
* Allocates and clears the buffer and creates the cairo surface.
|
||||
* @param width, height - the image size
|
||||
@@ -102,11 +120,13 @@ public class CairoSurface extends DataBuffer
|
||||
* with an affine transform given by i2u.
|
||||
*/
|
||||
public native void nativeDrawSurface(long surfacePointer, long contextPointer,
|
||||
double[] i2u, double alpha);
|
||||
double[] i2u, double alpha,
|
||||
int interpolation);
|
||||
|
||||
public void drawSurface(long contextPointer, double[] i2u, double alpha)
|
||||
public void drawSurface(long contextPointer, double[] i2u, double alpha,
|
||||
int interpolation)
|
||||
{
|
||||
nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha);
|
||||
nativeDrawSurface(surfacePointer, contextPointer, i2u, alpha, interpolation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,18 +158,20 @@ public class CairoSurface extends DataBuffer
|
||||
*/
|
||||
public CairoSurface(int width, int height)
|
||||
{
|
||||
super(DataBuffer.TYPE_INT, width * height);
|
||||
super(createCairoSampleModel(width, height),
|
||||
null, new Point(0, 0));
|
||||
|
||||
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);
|
||||
|
||||
if(surfacePointer == 0 || bufferPointer == 0)
|
||||
throw new Error("Could not allocate bitmap.");
|
||||
|
||||
dataBuffer = new CairoDataBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,18 +180,7 @@ public class CairoSurface extends DataBuffer
|
||||
*/
|
||||
CairoSurface(GtkImage image)
|
||||
{
|
||||
super(DataBuffer.TYPE_INT, image.width * image.height);
|
||||
|
||||
if(image.width <= 0 || image.height <= 0)
|
||||
throw new IllegalArgumentException("Image must be at least 1x1 pixels.");
|
||||
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
|
||||
create(width, height, width);
|
||||
|
||||
if(surfacePointer == 0 || bufferPointer == 0)
|
||||
throw new Error("Could not allocate bitmap.");
|
||||
this(image.width, image.height);
|
||||
|
||||
// Copy the pixel data from the GtkImage.
|
||||
int[] data = image.getPixels();
|
||||
@@ -260,32 +271,37 @@ public class CairoSurface extends DataBuffer
|
||||
*/
|
||||
public static BufferedImage getBufferedImage(CairoSurface surface)
|
||||
{
|
||||
WritableRaster raster = Raster.createPackedRaster
|
||||
(surface, surface.width, surface.height, surface.width,
|
||||
new int[]{ 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 },
|
||||
new Point(0,0));
|
||||
|
||||
return new BufferedImage(nativeModel, raster, true, new Hashtable());
|
||||
return new BufferedImage(cairoColorModel, surface,
|
||||
cairoColorModel.isAlphaPremultiplied(),
|
||||
new Hashtable());
|
||||
}
|
||||
|
||||
/**
|
||||
* DataBank.getElem implementation
|
||||
*/
|
||||
public int getElem(int bank, int i)
|
||||
private class CairoDataBuffer extends DataBuffer
|
||||
{
|
||||
if(bank != 0 || i < 0 || i >= width*height)
|
||||
throw new IndexOutOfBoundsException(i+" size: "+width*height);
|
||||
return nativeGetElem(bufferPointer, i);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* DataBank.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);
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,4 +335,14 @@ public class CairoSurface extends DataBuffer
|
||||
{
|
||||
copyAreaNative2(bufferPointer, x, y, width, height, dx, dy, stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SampleModel that matches Cairo's native format
|
||||
*/
|
||||
protected static SampleModel createCairoSampleModel(int w, int h)
|
||||
{
|
||||
return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
|
||||
new int[]{0x00FF0000, 0x0000FF00,
|
||||
0x000000FF, 0xFF000000});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,26 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
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;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Implementation of Graphics2D on a Cairo surface.
|
||||
@@ -49,6 +65,7 @@ import java.awt.geom.Rectangle2D;
|
||||
public class CairoSurfaceGraphics extends CairoGraphics2D
|
||||
{
|
||||
protected CairoSurface surface;
|
||||
private BufferedImage buffer;
|
||||
private long cairo_t;
|
||||
|
||||
/**
|
||||
@@ -59,6 +76,7 @@ public class CairoSurfaceGraphics extends CairoGraphics2D
|
||||
this.surface = surface;
|
||||
cairo_t = surface.newCairoContext();
|
||||
setup( cairo_t );
|
||||
setClip(0, 0, surface.width, surface.height);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,4 +109,200 @@ public class CairoSurfaceGraphics extends CairoGraphics2D
|
||||
{
|
||||
surface.copyAreaNative(x, y, width, height, dx, dy, surface.width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded methods that do actual drawing need to account for custom
|
||||
* composites
|
||||
*/
|
||||
public void draw(Shape s)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(Shape s)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRenderedImage(RenderedImage image, AffineTransform xform)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.drawRenderedImage(image, xform);
|
||||
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setRenderingHints(this.getRenderingHints());
|
||||
g2d.drawRenderedImage(image, xform);
|
||||
|
||||
drawComposite(buffer.getRaster().getBounds(), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean drawImage(Image img, AffineTransform xform,
|
||||
Color bgcolor, ImageObserver obs)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
return super.drawImage(img, xform, bgcolor, obs);
|
||||
|
||||
else
|
||||
{
|
||||
// Get buffered image of source
|
||||
if( !(img instanceof BufferedImage) )
|
||||
{
|
||||
ImageProducer source = img.getSource();
|
||||
if (source == null)
|
||||
return false;
|
||||
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(),
|
||||
bImg.getHeight() + bImg.getMinY());
|
||||
if (xform != null)
|
||||
{
|
||||
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
|
||||
return drawComposite(new Rectangle2D.Double(origin.getX(),
|
||||
origin.getY(),
|
||||
pt.getX(), pt.getY()),
|
||||
obs);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawGlyphVector(GlyphVector gv, float x, float y)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.drawGlyphVector(gv, x, y);
|
||||
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
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());
|
||||
drawComposite(bounds, null);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
BufferedImage current = CairoSurface.getBufferedImage(surface);
|
||||
current = current.getSubimage((int)deviceBounds.getX(),
|
||||
(int)deviceBounds.getY(),
|
||||
(int)deviceBounds.getWidth(),
|
||||
(int)deviceBounds.getHeight());
|
||||
|
||||
// Perform actual composite operation
|
||||
compCtx.compose(buffer2.getRaster(), current.getRaster(),
|
||||
buffer2.getRaster());
|
||||
|
||||
// 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);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
buffer = new BufferedImage(getBufferCM(),
|
||||
surface.createCompatibleWritableRaster(),
|
||||
getBufferCM().isAlphaPremultiplied(),
|
||||
new Hashtable());
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
|
||||
|
||||
g2d.setBackground(new Color(0,0,0,0));
|
||||
g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
protected ColorModel getNativeCM()
|
||||
{
|
||||
return CairoSurface.cairoCM_pre;
|
||||
}
|
||||
|
||||
protected ColorModel getBufferCM()
|
||||
{
|
||||
return CairoSurface.cairoColorModel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,22 +38,31 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import gnu.classpath.Pointer;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
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;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import gnu.classpath.Pointer;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* ComponentGraphics - context for drawing directly to a component,
|
||||
@@ -67,36 +76,11 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
|
||||
private GtkComponentPeer component;
|
||||
protected long cairo_t;
|
||||
private BufferedImage buffer, componentBuffer;
|
||||
|
||||
private static ThreadLocal hasLock = new ThreadLocal();
|
||||
private static Integer ONE = Integer.valueOf(1);
|
||||
|
||||
private void lock()
|
||||
{
|
||||
Integer i = (Integer) hasLock.get();
|
||||
if (i == null)
|
||||
{
|
||||
start_gdk_drawing();
|
||||
hasLock.set(ONE);
|
||||
}
|
||||
else
|
||||
hasLock.set(Integer.valueOf(i.intValue() + 1));
|
||||
}
|
||||
|
||||
private void unlock()
|
||||
{
|
||||
Integer i = (Integer) hasLock.get();
|
||||
if (i == null)
|
||||
throw new IllegalStateException();
|
||||
if (i == ONE)
|
||||
{
|
||||
hasLock.set(null);
|
||||
end_gdk_drawing();
|
||||
}
|
||||
else
|
||||
hasLock.set(Integer.valueOf(i.intValue() - 1));
|
||||
}
|
||||
|
||||
ComponentGraphics()
|
||||
{
|
||||
}
|
||||
@@ -128,6 +112,32 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
*/
|
||||
private native long initState(GtkComponentPeer component);
|
||||
|
||||
private void lock()
|
||||
{
|
||||
Integer i = (Integer) hasLock.get();
|
||||
if (i == null)
|
||||
{
|
||||
start_gdk_drawing();
|
||||
hasLock.set(ONE);
|
||||
}
|
||||
else
|
||||
hasLock.set(Integer.valueOf(i.intValue() + 1));
|
||||
}
|
||||
|
||||
private void unlock()
|
||||
{
|
||||
Integer i = (Integer) hasLock.get();
|
||||
if (i == null)
|
||||
throw new IllegalStateException();
|
||||
if (i == ONE)
|
||||
{
|
||||
hasLock.set(null);
|
||||
end_gdk_drawing();
|
||||
}
|
||||
else
|
||||
hasLock.set(Integer.valueOf(i.intValue() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the component surface and calls dispose on the cairo
|
||||
* graphics2d to destroy any super class resources.
|
||||
@@ -227,7 +237,20 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.draw(s);
|
||||
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);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -240,7 +263,20 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.fill(s);
|
||||
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);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -253,7 +289,19 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.drawRenderedImage(image, xform);
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.drawRenderedImage(image, xform);
|
||||
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setRenderingHints(this.getRenderingHints());
|
||||
g2d.drawRenderedImage(image, xform);
|
||||
|
||||
drawComposite(buffer.getRaster().getBounds(), null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -268,7 +316,44 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
lock();
|
||||
try
|
||||
{
|
||||
rv = super.drawImage(img, xform, bgcolor, obs);
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
rv = super.drawImage(img, xform, bgcolor, obs);
|
||||
|
||||
else
|
||||
{
|
||||
// Get buffered image of source
|
||||
if( !(img instanceof BufferedImage) )
|
||||
{
|
||||
ImageProducer source = img.getSource();
|
||||
if (source == null)
|
||||
return false;
|
||||
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(),
|
||||
bImg.getHeight() + bImg.getMinY());
|
||||
if (xform != null)
|
||||
{
|
||||
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()),
|
||||
obs);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -282,7 +367,23 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.drawGlyphVector(gv, x, y);
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.drawGlyphVector(gv, x, y);
|
||||
|
||||
else
|
||||
{
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
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());
|
||||
drawComposite(bounds, null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -367,6 +468,7 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
}
|
||||
|
||||
BufferedImage bimg;
|
||||
img = AsyncImage.realImage(img, observer);
|
||||
if (img instanceof BufferedImage)
|
||||
bimg = (BufferedImage) img;
|
||||
else
|
||||
@@ -379,45 +481,6 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
return super.drawImage(bimg, x, y, width, height, observer);
|
||||
}
|
||||
|
||||
public void drawLine(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.drawLine(x1, y1, x2, y2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawRect(int x, int y, int width, int height)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.drawRect(x, y, width, height);
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void fillRect(int x, int y, int width, int height)
|
||||
{
|
||||
lock();
|
||||
try
|
||||
{
|
||||
super.fillRect(x, y, width, height);
|
||||
}
|
||||
finally
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setClip(Shape s)
|
||||
{
|
||||
lock();
|
||||
@@ -431,5 +494,99 @@ public class ComponentGraphics extends CairoGraphics2D
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
// Get current image on the component
|
||||
unlock();
|
||||
GtkImage img = grab(component);
|
||||
Graphics gr = componentBuffer.createGraphics();
|
||||
gr.drawImage(img, 0, 0, null);
|
||||
gr.dispose();
|
||||
lock();
|
||||
|
||||
BufferedImage cBuffer = componentBuffer;
|
||||
if (!deviceBounds.equals(cBuffer.getRaster().getBounds()))
|
||||
cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(),
|
||||
(int)deviceBounds.getY(),
|
||||
(int)deviceBounds.getWidth(),
|
||||
(int)deviceBounds.getHeight());
|
||||
|
||||
// Perform actual composite operation
|
||||
compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(),
|
||||
cBuffer.getRaster());
|
||||
|
||||
// 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(cBuffer,
|
||||
AffineTransform.getTranslateInstance(bounds.getX(),
|
||||
bounds.getY()),
|
||||
null, null);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
WritableRaster rst;
|
||||
rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
|
||||
component.awtComponent.getHeight()),
|
||||
new Point(0,0));
|
||||
|
||||
buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
|
||||
GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
|
||||
new Hashtable());
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
|
||||
|
||||
g2d.setBackground(new Color(0,0,0,0));
|
||||
g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||
}
|
||||
|
||||
if (componentBuffer == null)
|
||||
{
|
||||
WritableRaster rst;
|
||||
rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
|
||||
component.awtComponent.getHeight()),
|
||||
new Point(0,0));
|
||||
|
||||
componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
|
||||
GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
|
||||
new Hashtable());
|
||||
}
|
||||
}
|
||||
|
||||
protected ColorModel getNativeCM()
|
||||
{
|
||||
return GtkVolatileImage.gdkColorModel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,14 +39,15 @@ package gnu.java.awt.peer.gtk;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphJustificationInfo;
|
||||
import java.awt.font.GlyphMetrics;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FreetypeGlyphVector extends GlyphVector
|
||||
{
|
||||
@@ -91,16 +92,17 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
*/
|
||||
public FreetypeGlyphVector(Font f, String s, FontRenderContext frc)
|
||||
{
|
||||
this(f, s, frc, Font.LAYOUT_LEFT_TO_RIGHT);
|
||||
this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a glyphvector from a given (Freetype) font and a String.
|
||||
*/
|
||||
public FreetypeGlyphVector(Font f, String s, FontRenderContext frc,
|
||||
int flags)
|
||||
public FreetypeGlyphVector(Font f, char[] chars, int start, int len,
|
||||
FontRenderContext frc, int flags)
|
||||
{
|
||||
this.s = s;
|
||||
this.s = new String(chars, start, len);
|
||||
|
||||
this.font = f;
|
||||
this.frc = frc;
|
||||
if( !(font.getPeer() instanceof GdkFontPeer ) )
|
||||
@@ -155,14 +157,15 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
}
|
||||
|
||||
glyphCodes = new int[ nGlyphs ];
|
||||
glyphPositions = new float[ nGlyphs ];
|
||||
glyphPositions = new float[(nGlyphs + 1) * 2];
|
||||
glyphTransforms = new AffineTransform[ nGlyphs ];
|
||||
for(int i = 0; i < nGlyphs; i++ )
|
||||
{
|
||||
glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
|
||||
glyphCodes[i] = gv.glyphCodes[ i ];
|
||||
glyphPositions[i] = gv.glyphPositions[ i ];
|
||||
glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
|
||||
glyphCodes[i] = gv.glyphCodes[ i ];
|
||||
}
|
||||
System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0,
|
||||
glyphPositions.length);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,10 +181,17 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
for(int i = 0; i < nGlyphs; i++)
|
||||
{
|
||||
codePoints[i] = s.codePointAt( stringIndex );
|
||||
// UTF32 surrogate handling
|
||||
// UTF32 surrogate handling
|
||||
if( codePoints[i] != (int)s.charAt( stringIndex ) )
|
||||
stringIndex ++;
|
||||
stringIndex ++;
|
||||
|
||||
if (Character.isISOControl(codePoints[i]))
|
||||
{
|
||||
// Replace with 'hair space'. Should better be 'zero-width space'
|
||||
// but that doesn't seem to be supported by default font.
|
||||
codePoints[i] = 8202;
|
||||
}
|
||||
}
|
||||
|
||||
glyphCodes = getGlyphs( codePoints );
|
||||
@@ -242,22 +252,31 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
public void performDefaultLayout()
|
||||
{
|
||||
logicalBounds = null; // invalidate caches.
|
||||
glyphPositions = null;
|
||||
|
||||
glyphTransforms = new AffineTransform[ nGlyphs ];
|
||||
double x = 0;
|
||||
glyphTransforms = new AffineTransform[nGlyphs];
|
||||
Arrays.fill(glyphTransforms, null);
|
||||
glyphPositions = new float[(nGlyphs + 1) * 2];
|
||||
|
||||
GlyphMetrics gm = null;
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
for(int i = 0; i < nGlyphs; i++)
|
||||
{
|
||||
GlyphMetrics gm = getGlyphMetrics( i );
|
||||
glyphTransforms[ i ] = AffineTransform.getTranslateInstance(x, 0);
|
||||
x += gm.getAdvanceX();
|
||||
if( i > 0 )
|
||||
{
|
||||
Point2D p = getKerning( glyphCodes[ i - 1 ], glyphCodes[ i ] );
|
||||
x += p.getX();
|
||||
}
|
||||
gm = getGlyphMetrics( i );
|
||||
glyphPositions[i*2] = x;
|
||||
glyphPositions[i*2 + 1] = y;
|
||||
|
||||
x += gm.getAdvanceX();
|
||||
y += gm.getAdvanceY();
|
||||
|
||||
if (i != nGlyphs-1)
|
||||
{
|
||||
Point2D p = getKerning(glyphCodes[i], glyphCodes[i + 1]);
|
||||
x += p.getX();
|
||||
y += p.getY();
|
||||
}
|
||||
}
|
||||
glyphPositions[nGlyphs * 2] = x;
|
||||
glyphPositions[nGlyphs * 2 + 1] = y;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +295,7 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
{
|
||||
int[] rval;
|
||||
|
||||
if( codeReturn == null )
|
||||
if( codeReturn == null || codeReturn.length < numEntries)
|
||||
rval = new int[ numEntries ];
|
||||
else
|
||||
rval = codeReturn;
|
||||
@@ -286,9 +305,6 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME: Implement me.
|
||||
*/
|
||||
public Shape getGlyphLogicalBounds(int glyphIndex)
|
||||
{
|
||||
GlyphMetrics gm = getGlyphMetrics( glyphIndex );
|
||||
@@ -296,10 +312,17 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
return null;
|
||||
Rectangle2D r = gm.getBounds2D();
|
||||
Point2D p = getGlyphPosition( glyphIndex );
|
||||
return new Rectangle2D.Double( p.getX() + r.getX() - gm.getLSB(),
|
||||
p.getY() + r.getY(),
|
||||
gm.getAdvanceX(),
|
||||
r.getHeight() );
|
||||
|
||||
double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(),
|
||||
p.getY() + r.getY(),
|
||||
p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(),
|
||||
p.getY() + r.getY() + r.getHeight()};
|
||||
|
||||
if (glyphTransforms[glyphIndex] != null)
|
||||
glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 4);
|
||||
|
||||
return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0],
|
||||
bounds[3] - bounds[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -352,7 +375,9 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
public Shape getGlyphOutline(int glyphIndex)
|
||||
{
|
||||
GeneralPath gp = getGlyphOutlineNative( glyphCodes[ glyphIndex ] );
|
||||
gp.transform( glyphTransforms[ glyphIndex ] );
|
||||
if (glyphTransforms[glyphIndex] != null)
|
||||
gp.transform( glyphTransforms[glyphIndex]);
|
||||
|
||||
return gp;
|
||||
}
|
||||
|
||||
@@ -361,8 +386,8 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
*/
|
||||
public Point2D getGlyphPosition(int glyphIndex)
|
||||
{
|
||||
return glyphTransforms[ glyphIndex ].transform( new Point2D.Double(0, 0),
|
||||
null );
|
||||
return new Point2D.Float(glyphPositions[glyphIndex*2],
|
||||
glyphPositions[glyphIndex*2 + 1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,25 +396,12 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
public float[] getGlyphPositions(int beginGlyphIndex, int numEntries,
|
||||
float[] positionReturn)
|
||||
{
|
||||
if( glyphPositions != null )
|
||||
return glyphPositions;
|
||||
|
||||
float[] rval;
|
||||
|
||||
if( positionReturn == null )
|
||||
rval = new float[2 * numEntries];
|
||||
else
|
||||
rval = positionReturn;
|
||||
|
||||
for( int i = beginGlyphIndex; i < numEntries; i++ )
|
||||
{
|
||||
Point2D p = getGlyphPosition( i );
|
||||
rval[i * 2] = (float)p.getX();
|
||||
rval[i * 2 + 1] = (float)p.getY();
|
||||
}
|
||||
|
||||
glyphPositions = rval;
|
||||
return rval;
|
||||
if (positionReturn == null || positionReturn.length < (numEntries * 2))
|
||||
positionReturn = new float[numEntries*2];
|
||||
|
||||
System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0,
|
||||
numEntries*2);
|
||||
return positionReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,7 +409,7 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
*/
|
||||
public AffineTransform getGlyphTransform(int glyphIndex)
|
||||
{
|
||||
return new AffineTransform( glyphTransforms[ glyphIndex ] );
|
||||
return glyphTransforms[glyphIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -420,10 +432,12 @@ 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 );
|
||||
rect = rect.createUnion( r2 );
|
||||
Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
|
||||
|
||||
rect = rect.createUnion( r2 );
|
||||
}
|
||||
|
||||
logicalBounds = rect;
|
||||
@@ -444,8 +458,14 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
public Shape getOutline()
|
||||
{
|
||||
GeneralPath path = new GeneralPath();
|
||||
AffineTransform tx = new AffineTransform();
|
||||
for( int i = 0; i < getNumGlyphs(); i++ )
|
||||
path.append( getGlyphOutline( i ), false );
|
||||
{
|
||||
Shape outline = getGlyphOutline(i);
|
||||
tx.setToTranslation(glyphPositions[i*2], glyphPositions[i*2 +1]);
|
||||
outline = tx.createTransformedShape(outline);
|
||||
path.append(outline, false);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -485,11 +505,9 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
*/
|
||||
public void setGlyphPosition(int glyphIndex, Point2D newPos)
|
||||
{
|
||||
// FIXME: Scaling, etc.?
|
||||
glyphTransforms[ glyphIndex ].setToTranslation( newPos.getX(),
|
||||
newPos.getY() );
|
||||
glyphPositions[glyphIndex*2] = (float)(newPos.getX());
|
||||
glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY());
|
||||
logicalBounds = null;
|
||||
glyphPositions = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,8 +515,7 @@ public class FreetypeGlyphVector extends GlyphVector
|
||||
*/
|
||||
public void setGlyphTransform(int glyphIndex, AffineTransform newTX)
|
||||
{
|
||||
glyphTransforms[ glyphIndex ].setTransform( newTX );
|
||||
logicalBounds = null;
|
||||
glyphPositions = null;
|
||||
glyphTransforms[glyphIndex] = newTX;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
/* GdkFontMetrics.java
|
||||
Copyright (C) 1999, 2002, 2004, 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import gnu.java.awt.ClasspathToolkit;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Toolkit;
|
||||
|
||||
public class GdkFontMetrics extends FontMetrics
|
||||
{
|
||||
|
||||
private int[] font_metrics;
|
||||
GdkFontPeer peer;
|
||||
|
||||
static final int FONT_METRICS_ASCENT = 0;
|
||||
static final int FONT_METRICS_MAX_ASCENT = 1;
|
||||
static final int FONT_METRICS_DESCENT = 2;
|
||||
static final int FONT_METRICS_MAX_DESCENT = 3;
|
||||
static final int FONT_METRICS_MAX_ADVANCE = 4;
|
||||
|
||||
static final int TEXT_METRICS_X_BEARING = 0;
|
||||
static final int TEXT_METRICS_Y_BEARING = 1;
|
||||
static final int TEXT_METRICS_WIDTH = 2;
|
||||
static final int TEXT_METRICS_HEIGHT = 3;
|
||||
static final int TEXT_METRICS_X_ADVANCE = 4;
|
||||
static final int TEXT_METRICS_Y_ADVANCE = 5;
|
||||
|
||||
/**
|
||||
* Makes sure to return a Font based on the given Font that has as
|
||||
* peer a GdkFontPeer. Used in the initializer.
|
||||
*/
|
||||
private static Font initFont(Font font)
|
||||
{
|
||||
if (font == null)
|
||||
return new Font("Dialog", Font.PLAIN, 12);
|
||||
else if (font.getPeer() instanceof GdkFontPeer)
|
||||
return font;
|
||||
else
|
||||
{
|
||||
ClasspathToolkit toolkit;
|
||||
toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit();
|
||||
return toolkit.getFont(font.getName(), font.getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
public GdkFontMetrics (Font font)
|
||||
{
|
||||
super(initFont(font));
|
||||
peer = (GdkFontPeer) this.font.getPeer();
|
||||
|
||||
font_metrics = new int[5];
|
||||
double [] hires = new double[5];
|
||||
peer.getFontMetrics (hires);
|
||||
for (int i = 0; i < 5; ++i)
|
||||
font_metrics[i] = (int) hires[i];
|
||||
}
|
||||
|
||||
public int stringWidth (String str)
|
||||
{
|
||||
double [] hires = new double[6];
|
||||
peer.getTextMetrics(str, hires);
|
||||
return (int) hires [TEXT_METRICS_WIDTH];
|
||||
}
|
||||
|
||||
public int charWidth (char ch)
|
||||
{
|
||||
return stringWidth (new String (new char[] { ch }));
|
||||
}
|
||||
|
||||
public int charsWidth (char data[], int off, int len)
|
||||
{
|
||||
return stringWidth (new String (data, off, len));
|
||||
}
|
||||
|
||||
public int getLeading ()
|
||||
{
|
||||
// Sun always returns 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getAscent ()
|
||||
{
|
||||
return font_metrics[FONT_METRICS_ASCENT];
|
||||
}
|
||||
|
||||
public int getMaxAscent ()
|
||||
{
|
||||
return font_metrics[FONT_METRICS_MAX_ASCENT];
|
||||
}
|
||||
|
||||
public int getDescent ()
|
||||
{
|
||||
return font_metrics[FONT_METRICS_DESCENT];
|
||||
}
|
||||
|
||||
public int getMaxDescent ()
|
||||
{
|
||||
return font_metrics[FONT_METRICS_MAX_DESCENT];
|
||||
}
|
||||
|
||||
public int getMaxAdvance ()
|
||||
{
|
||||
return font_metrics[FONT_METRICS_MAX_ADVANCE];
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import gnu.java.awt.ClasspathToolkit;
|
||||
import gnu.java.awt.peer.ClasspathFontPeer;
|
||||
import gnu.java.awt.font.opentype.NameDecoder;
|
||||
|
||||
@@ -48,39 +49,125 @@ import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.GlyphMetrics;
|
||||
import java.awt.font.LineMetrics;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.text.CharacterIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class GdkFontPeer extends ClasspathFontPeer
|
||||
{
|
||||
static final FontRenderContext DEFAULT_CTX =
|
||||
new FontRenderContext(null, false, false);
|
||||
|
||||
/**
|
||||
* Caches TextLayout instances for use in charsWidth() and drawString().
|
||||
* 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);
|
||||
|
||||
private class GdkFontMetrics extends FontMetrics
|
||||
{
|
||||
|
||||
public GdkFontMetrics (Font font)
|
||||
{
|
||||
super(initFont(font));
|
||||
}
|
||||
|
||||
public int stringWidth (String str)
|
||||
{
|
||||
TextLayout tl = (TextLayout) textLayoutCache.get(str);
|
||||
if (tl == null)
|
||||
{
|
||||
tl = new TextLayout(str, font, DEFAULT_CTX);
|
||||
textLayoutCache.put(str, tl);
|
||||
}
|
||||
return (int) tl.getAdvance();
|
||||
}
|
||||
|
||||
public int charWidth (char ch)
|
||||
{
|
||||
return stringWidth (new String (new char[] { ch }));
|
||||
}
|
||||
|
||||
public int charsWidth (char data[], int off, int len)
|
||||
{
|
||||
return stringWidth (new String (data, off, len));
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return (int) height;
|
||||
}
|
||||
|
||||
public int getLeading ()
|
||||
{
|
||||
return (int) (height - (ascent + descent));
|
||||
}
|
||||
|
||||
public int getAscent ()
|
||||
{
|
||||
return (int) ascent;
|
||||
}
|
||||
|
||||
public int getMaxAscent ()
|
||||
{
|
||||
return (int) ascent;
|
||||
}
|
||||
|
||||
public int getDescent ()
|
||||
{
|
||||
return (int) descent;
|
||||
}
|
||||
|
||||
public int getMaxDescent ()
|
||||
{
|
||||
return (int) maxDescent;
|
||||
}
|
||||
|
||||
public int getMaxAdvance ()
|
||||
{
|
||||
return (int) maxAdvance;
|
||||
}
|
||||
}
|
||||
|
||||
static native void initStaticState();
|
||||
private final int native_state = GtkGenericPeer.getUniqueInteger ();
|
||||
private static ResourceBundle bundle;
|
||||
|
||||
/**
|
||||
* Cache GlyphMetrics objects.
|
||||
*/
|
||||
private HashMap metricsCache;
|
||||
|
||||
|
||||
private static final int FONT_METRICS_ASCENT = 0;
|
||||
private static final int FONT_METRICS_MAX_ASCENT = 1;
|
||||
private static final int FONT_METRICS_DESCENT = 2;
|
||||
private static final int FONT_METRICS_MAX_DESCENT = 3;
|
||||
private static final int FONT_METRICS_MAX_ADVANCE = 4;
|
||||
private static final int FONT_METRICS_HEIGHT = 5;
|
||||
private static final int FONT_METRICS_UNDERLINE_OFFSET = 6;
|
||||
private static final int FONT_METRICS_UNDERLINE_THICKNESS = 7;
|
||||
|
||||
float ascent;
|
||||
float descent;
|
||||
float maxAscent;
|
||||
float maxDescent;
|
||||
float maxAdvance;
|
||||
float height;
|
||||
float underlineOffset;
|
||||
float underlineThickness;
|
||||
|
||||
GdkFontMetrics metrics;
|
||||
|
||||
static
|
||||
{
|
||||
System.loadLibrary("gtkpeer");
|
||||
|
||||
initStaticState ();
|
||||
|
||||
try
|
||||
{
|
||||
bundle = ResourceBundle.getBundle ("gnu.java.awt.peer.gtk.font");
|
||||
}
|
||||
catch (Throwable ignored)
|
||||
{
|
||||
bundle = null;
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer nameTable = null;
|
||||
@@ -89,8 +176,8 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
private native void dispose ();
|
||||
private native void setFont (String family, int style, int size);
|
||||
|
||||
native void getFontMetrics(double [] metrics);
|
||||
native void getTextMetrics(String str, double [] metrics);
|
||||
native synchronized void getFontMetrics(double [] metrics);
|
||||
native synchronized void getTextMetrics(String str, double [] metrics);
|
||||
|
||||
native void releasePeerGraphicsResource();
|
||||
|
||||
@@ -149,6 +236,7 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
initState ();
|
||||
setFont (this.familyName, this.style, (int)this.size);
|
||||
metricsCache = new HashMap();
|
||||
setupMetrics();
|
||||
}
|
||||
|
||||
public GdkFontPeer (String name, Map attributes)
|
||||
@@ -157,6 +245,40 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
initState ();
|
||||
setFont (this.familyName, this.style, (int)this.size);
|
||||
metricsCache = new HashMap();
|
||||
setupMetrics();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes sure to return a Font based on the given Font that has as
|
||||
* peer a GdkFontPeer. Used in the initializer.
|
||||
*/
|
||||
static Font initFont(Font font)
|
||||
{
|
||||
if (font == null)
|
||||
return new Font("Dialog", Font.PLAIN, 12);
|
||||
else if (font.getPeer() instanceof GdkFontPeer)
|
||||
return font;
|
||||
else
|
||||
{
|
||||
ClasspathToolkit toolkit;
|
||||
toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit();
|
||||
return toolkit.getFont(font.getName(), font.getAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
private void setupMetrics()
|
||||
{
|
||||
double [] hires = new double[8];
|
||||
getFontMetrics(hires);
|
||||
ascent = (float) hires[FONT_METRICS_ASCENT];
|
||||
maxAscent = (float) hires[FONT_METRICS_MAX_ASCENT];
|
||||
descent = (float) hires[FONT_METRICS_DESCENT];
|
||||
maxDescent = (float) hires[FONT_METRICS_MAX_DESCENT];
|
||||
maxAdvance = (float) hires[FONT_METRICS_MAX_ADVANCE];
|
||||
height = (float) hires[FONT_METRICS_HEIGHT];
|
||||
underlineOffset = (float) hires[FONT_METRICS_UNDERLINE_OFFSET];
|
||||
underlineThickness = (float) hires[FONT_METRICS_UNDERLINE_THICKNESS];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,26 +383,17 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
return Font.ROMAN_BASELINE;
|
||||
}
|
||||
|
||||
private static class GdkFontLineMetrics extends LineMetrics
|
||||
private class GdkFontLineMetrics extends LineMetrics
|
||||
{
|
||||
private FontMetrics fm;
|
||||
private int nchars;
|
||||
private float strikethroughOffset, strikethroughThickness,
|
||||
underlineOffset, underlineThickness;
|
||||
|
||||
public GdkFontLineMetrics (GdkFontPeer fp, FontMetrics m, int n)
|
||||
private int nchars;
|
||||
public GdkFontLineMetrics (GdkFontPeer fp, int n)
|
||||
{
|
||||
fm = m;
|
||||
nchars = n;
|
||||
strikethroughOffset = 0f;
|
||||
underlineOffset = 0f;
|
||||
strikethroughThickness = ((float)fp.getSize(null)) / 12f;
|
||||
underlineThickness = strikethroughThickness;
|
||||
}
|
||||
|
||||
public float getAscent()
|
||||
{
|
||||
return (float) fm.getAscent ();
|
||||
return ascent;
|
||||
}
|
||||
|
||||
public int getBaselineIndex()
|
||||
@@ -296,27 +409,52 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
|
||||
public float getDescent()
|
||||
{
|
||||
return (float) fm.getDescent ();
|
||||
return descent;
|
||||
}
|
||||
|
||||
public float getHeight()
|
||||
{
|
||||
return (float) fm.getHeight ();
|
||||
return height;
|
||||
}
|
||||
|
||||
public float getLeading() { return 0.f; }
|
||||
public int getNumChars() { return nchars; }
|
||||
public float getStrikethroughOffset() { return 0.f; }
|
||||
public float getStrikethroughThickness() { return 0.f; }
|
||||
public float getUnderlineOffset() { return 0.f; }
|
||||
public float getUnderlineThickness() { return 0.f; }
|
||||
public float getLeading()
|
||||
{
|
||||
return height - (ascent + descent);
|
||||
}
|
||||
|
||||
public int getNumChars()
|
||||
{
|
||||
return nchars;
|
||||
}
|
||||
|
||||
public float getStrikethroughOffset()
|
||||
{
|
||||
// FreeType doesn't seem to provide a value here.
|
||||
return ascent / 2;
|
||||
}
|
||||
|
||||
public float getStrikethroughThickness()
|
||||
{
|
||||
// FreeType doesn't seem to provide a value here.
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
public float getUnderlineOffset()
|
||||
{
|
||||
return underlineOffset;
|
||||
}
|
||||
|
||||
public float getUnderlineThickness()
|
||||
{
|
||||
return underlineThickness;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LineMetrics getLineMetrics (Font font, CharacterIterator ci,
|
||||
int begin, int limit, FontRenderContext rc)
|
||||
{
|
||||
return new GdkFontLineMetrics (this, getFontMetrics (font), limit - begin);
|
||||
return new GdkFontLineMetrics (this, limit - begin);
|
||||
}
|
||||
|
||||
public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc)
|
||||
@@ -345,15 +483,6 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
return buf.getShort(4);
|
||||
}
|
||||
|
||||
public Rectangle2D getStringBounds (Font font, CharacterIterator ci,
|
||||
int begin, int limit, FontRenderContext frc)
|
||||
{
|
||||
GlyphVector gv = new FreetypeGlyphVector( font,
|
||||
buildString(ci, begin, limit),
|
||||
frc);
|
||||
return gv.getVisualBounds();
|
||||
}
|
||||
|
||||
public boolean hasUniformLineMetrics (Font font)
|
||||
{
|
||||
return true;
|
||||
@@ -363,22 +492,21 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
char[] chars, int start, int limit,
|
||||
int flags)
|
||||
{
|
||||
return new FreetypeGlyphVector( font, new String( chars, start,
|
||||
limit - start),
|
||||
return new FreetypeGlyphVector( font, chars, start, limit - start,
|
||||
frc, flags);
|
||||
}
|
||||
|
||||
public LineMetrics getLineMetrics (Font font, String str,
|
||||
FontRenderContext frc)
|
||||
{
|
||||
return new GdkFontLineMetrics (this, getFontMetrics (font), str.length ());
|
||||
return new GdkFontLineMetrics (this, str.length ());
|
||||
}
|
||||
|
||||
public FontMetrics getFontMetrics (Font font)
|
||||
{
|
||||
// Get the font metrics through GtkToolkit to take advantage of
|
||||
// the metrics cache.
|
||||
return Toolkit.getDefaultToolkit().getFontMetrics (font);
|
||||
if (metrics == null)
|
||||
metrics = new GdkFontMetrics(font);
|
||||
return metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,4 +525,5 @@ public class GdkFontPeer extends ClasspathFontPeer
|
||||
{
|
||||
metricsCache.put( new Integer( glyphCode ), metrics );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.Raster;
|
||||
import java.util.Locale;
|
||||
|
||||
public class GdkGraphicsEnvironment extends GraphicsEnvironment
|
||||
@@ -103,9 +103,9 @@ public class GdkGraphicsEnvironment extends GraphicsEnvironment
|
||||
|
||||
public Graphics2D createGraphics (BufferedImage image)
|
||||
{
|
||||
DataBuffer db = image.getRaster().getDataBuffer();
|
||||
if(db instanceof CairoSurface)
|
||||
return ((CairoSurface)db).getGraphics();
|
||||
Raster raster = image.getRaster();
|
||||
if(raster instanceof CairoSurface)
|
||||
return ((CairoSurface)raster).getGraphics();
|
||||
|
||||
return new BufferedImageGraphics( image );
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class GtkChoicePeer extends GtkComponentPeer
|
||||
|
||||
public void select (int position)
|
||||
{
|
||||
if (Thread.currentThread() == GtkToolkit.mainThread)
|
||||
if (Thread.currentThread() == GtkMainThread.mainThread)
|
||||
selectNativeUnlocked (position);
|
||||
else
|
||||
selectNative (position);
|
||||
|
||||
@@ -90,6 +90,11 @@ public class GtkComponentPeer extends GtkGenericPeer
|
||||
|
||||
Insets insets;
|
||||
|
||||
/**
|
||||
* The current repaint area. Use should be guarded by synchronizing on this.
|
||||
*/
|
||||
private Rectangle currentPaintArea;
|
||||
|
||||
/* this isEnabled differs from Component.isEnabled, in that it
|
||||
knows if a parent is disabled. In that case Component.isEnabled
|
||||
may return true, but our isEnabled will always return false */
|
||||
@@ -308,13 +313,30 @@ public class GtkComponentPeer extends GtkGenericPeer
|
||||
// seems expensive. However, the graphics state does not carry
|
||||
// over between calls to paint, and resetting the graphics object
|
||||
// may even be more costly than simply creating a new one.
|
||||
Graphics g = getGraphics();
|
||||
|
||||
g.setClip(event.getUpdateRect());
|
||||
// Make sure that the paintArea includes the area from the event
|
||||
// in the case when an application sends PaintEvents directly.
|
||||
coalescePaintEvent(event);
|
||||
Rectangle paintArea;
|
||||
synchronized (this)
|
||||
{
|
||||
paintArea = currentPaintArea;
|
||||
currentPaintArea = null;
|
||||
}
|
||||
|
||||
awtComponent.paint(g);
|
||||
|
||||
g.dispose();
|
||||
if (paintArea != null)
|
||||
{
|
||||
Graphics g = getGraphics();
|
||||
try
|
||||
{
|
||||
g.setClip(paintArea);
|
||||
awtComponent.paint(g);
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method and its overrides are the only methods in the peers
|
||||
@@ -327,13 +349,29 @@ public class GtkComponentPeer extends GtkGenericPeer
|
||||
|| (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1))
|
||||
return;
|
||||
|
||||
Graphics g = getGraphics();
|
||||
// Make sure that the paintArea includes the area from the event
|
||||
// in the case when an application sends PaintEvents directly.
|
||||
coalescePaintEvent(event);
|
||||
Rectangle paintArea;
|
||||
synchronized (this)
|
||||
{
|
||||
paintArea = currentPaintArea;
|
||||
currentPaintArea = null;
|
||||
}
|
||||
|
||||
g.setClip(event.getUpdateRect());
|
||||
|
||||
awtComponent.update(g);
|
||||
|
||||
g.dispose();
|
||||
if (paintArea != null)
|
||||
{
|
||||
Graphics g = getGraphics();
|
||||
try
|
||||
{
|
||||
g.setClip(paintArea);
|
||||
awtComponent.update(g);
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFocusTraversable ()
|
||||
@@ -514,7 +552,7 @@ public class GtkComponentPeer extends GtkGenericPeer
|
||||
y = 0;
|
||||
}
|
||||
|
||||
if (Thread.currentThread() == GtkToolkit.mainThread)
|
||||
if (Thread.currentThread() == GtkMainThread.mainThread)
|
||||
gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y);
|
||||
else
|
||||
gtkWidgetSetCursor(cursor.getType(), image, x, y);
|
||||
@@ -562,7 +600,7 @@ public class GtkComponentPeer extends GtkGenericPeer
|
||||
b = (bounds.width > 0) && (bounds.height > 0);
|
||||
}
|
||||
|
||||
if (Thread.currentThread() == GtkToolkit.mainThread)
|
||||
if (Thread.currentThread() == GtkMainThread.mainThread)
|
||||
setVisibleNativeUnlocked (b);
|
||||
else
|
||||
setVisibleNative (b);
|
||||
@@ -754,7 +792,14 @@ public class GtkComponentPeer extends GtkGenericPeer
|
||||
|
||||
public void coalescePaintEvent (PaintEvent e)
|
||||
{
|
||||
|
||||
synchronized (this)
|
||||
{
|
||||
Rectangle newRect = e.getUpdateRect();
|
||||
if (currentPaintArea == null)
|
||||
currentPaintArea = newRect;
|
||||
else
|
||||
Rectangle.union(currentPaintArea, newRect, currentPaintArea);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCursorImmediately ()
|
||||
|
||||
@@ -57,6 +57,11 @@ public class GtkFramePeer extends GtkWindowPeer
|
||||
native void removeMenuBarPeer ();
|
||||
native void gtkFixedSetVisible (boolean visible);
|
||||
|
||||
private native void maximize();
|
||||
private native void unmaximize();
|
||||
private native void iconify();
|
||||
private native void deiconify();
|
||||
|
||||
int getMenuBarHeight ()
|
||||
{
|
||||
return menuBar == null ? 0 : getMenuBarHeight (menuBar);
|
||||
@@ -199,12 +204,25 @@ public class GtkFramePeer extends GtkWindowPeer
|
||||
|
||||
public int getState ()
|
||||
{
|
||||
return 0;
|
||||
return windowState;
|
||||
}
|
||||
|
||||
public void setState (int state)
|
||||
{
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case Frame.NORMAL:
|
||||
if ((windowState & Frame.ICONIFIED) != 0)
|
||||
deiconify();
|
||||
if ((windowState & Frame.MAXIMIZED_BOTH) != 0)
|
||||
unmaximize();
|
||||
break;
|
||||
case Frame.ICONIFIED:
|
||||
iconify();
|
||||
break;
|
||||
case Frame.MAXIMIZED_BOTH:
|
||||
maximize();
|
||||
}
|
||||
}
|
||||
|
||||
public void setMaximizedBounds (Rectangle r)
|
||||
|
||||
@@ -42,6 +42,7 @@ import java.awt.image.ColorModel;
|
||||
import java.awt.image.ImageConsumer;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.MemoryImageSource;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
@@ -103,7 +104,7 @@ public class GtkImageConsumer implements ImageConsumer
|
||||
scansize);
|
||||
}
|
||||
|
||||
public synchronized void setPixels (int x, int y, int width, int height,
|
||||
public synchronized void setPixels (int x, int y, int width, int height,
|
||||
ColorModel cm, int[] pixels,
|
||||
int offset, int scansize)
|
||||
{
|
||||
@@ -117,18 +118,34 @@ public class GtkImageConsumer implements ImageConsumer
|
||||
width);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/* GtkMainThread.java -- Wrapper for the GTK main thread, and some utilities.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import 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()
|
||||
* returns. That happens in response to the last window peer being
|
||||
* disposed (see GtkWindowPeer.dispose).
|
||||
*
|
||||
* When GtkMainThread.destroyWindow is called for the last window, it
|
||||
* in turn calls GtkMainThread.endMainThread, which calls gtk_quit.
|
||||
* gtk_quit signals gtk_main to return, which causes GtkMainThread.run
|
||||
* to return.
|
||||
*
|
||||
* There should only be one native GTK main loop running at any given
|
||||
* time. In order to safely start and stop the GTK main loop, we use
|
||||
* a running flag and corresponding runningLock. startMainThread will
|
||||
* not return until the native GTK main loop has started, as confirmed
|
||||
* by the native set_running_flag callback setting the running flag to
|
||||
* true. Without this protection, gtk_quit could be called before the
|
||||
* main loop has actually started, which causes GTK assertion
|
||||
* failures. Likewise endMainThread will not return until the native
|
||||
* GTK main loop has ended.
|
||||
*
|
||||
* post_running_flag_callback is called during gtk_main initialization
|
||||
* and no window can be created before startMainThread returns. This
|
||||
* ensures that calling post_running_flag_callback is the first action
|
||||
* taken by the native GTK main loop.
|
||||
*
|
||||
* GtkMainThread.mainThread is started when the window count goes from
|
||||
* zero to one.
|
||||
*
|
||||
* GtkMainThread keeps the AWT event queue informed of its status by
|
||||
* posting NativeEventLoopRunningEvents. The AWT event queue uses
|
||||
* this status to determine whether or not the AWT exit conditions
|
||||
* have been met (see EventQueue.isShutdown).
|
||||
*/
|
||||
public class GtkMainThread extends Thread
|
||||
{
|
||||
/** Count of the number of open windows */
|
||||
private static int numberOfWindows = 0;
|
||||
|
||||
/** Lock for the above */
|
||||
private static Object nWindowsLock = new Object();
|
||||
|
||||
/** Indicates whether or not the GTK main loop is running. */
|
||||
private static boolean running = false;
|
||||
|
||||
/** Lock for the above. */
|
||||
private static Object runningLock = new Object();
|
||||
|
||||
/** The main thread instance (singleton) */
|
||||
public static GtkMainThread mainThread;
|
||||
|
||||
/** Constructs a main thread */
|
||||
private GtkMainThread()
|
||||
{
|
||||
super("GTK main thread");
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
GtkToolkit.gtkMain ();
|
||||
}
|
||||
|
||||
private static void setRunning(boolean running)
|
||||
{
|
||||
synchronized (runningLock)
|
||||
{
|
||||
GtkMainThread.running = running;
|
||||
runningLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private static void startMainThread()
|
||||
{
|
||||
synchronized (runningLock)
|
||||
{
|
||||
if (!running)
|
||||
{
|
||||
mainThread = new GtkMainThread();
|
||||
mainThread.start();
|
||||
|
||||
while (!running)
|
||||
{
|
||||
try
|
||||
{
|
||||
runningLock.wait();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
System.err.println ("GtkMainThread.startMainThread:"
|
||||
+ " interrupted while waiting "
|
||||
+ " for GTK main loop to start");
|
||||
}
|
||||
}
|
||||
GtkGenericPeer.q()
|
||||
.postEvent(new NativeEventLoopRunningEvent(new Boolean(true)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void endMainThread()
|
||||
{
|
||||
synchronized (runningLock)
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
GtkToolkit.gtkQuit();
|
||||
|
||||
while (running)
|
||||
{
|
||||
try
|
||||
{
|
||||
runningLock.wait();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
System.err.println ("GtkMainThread.endMainThread:"
|
||||
+ " interrupted while waiting "
|
||||
+ " for GTK main loop to stop");
|
||||
}
|
||||
}
|
||||
GtkGenericPeer.q()
|
||||
.postEvent(new NativeEventLoopRunningEvent(new Boolean(false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void createWindow()
|
||||
{
|
||||
synchronized (nWindowsLock)
|
||||
{
|
||||
if (numberOfWindows == 0)
|
||||
startMainThread();
|
||||
numberOfWindows++;
|
||||
}
|
||||
}
|
||||
|
||||
public static void destroyWindow()
|
||||
{
|
||||
synchronized (nWindowsLock)
|
||||
{
|
||||
numberOfWindows--;
|
||||
if (numberOfWindows == 0)
|
||||
endMainThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ import java.awt.FontMetrics;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.Label;
|
||||
import java.awt.List;
|
||||
@@ -83,6 +84,7 @@ import java.awt.dnd.DragGestureEvent;
|
||||
import java.awt.dnd.DragGestureListener;
|
||||
import java.awt.dnd.DragGestureRecognizer;
|
||||
import java.awt.dnd.DragSource;
|
||||
import java.awt.dnd.InvalidDnDOperationException;
|
||||
import java.awt.dnd.peer.DragSourceContextPeer;
|
||||
import java.awt.im.InputMethodHighlight;
|
||||
import java.awt.image.ColorModel;
|
||||
@@ -115,7 +117,6 @@ import java.awt.peer.WindowPeer;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -131,37 +132,30 @@ import javax.imageio.spi.IIORegistry;
|
||||
|
||||
public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
{
|
||||
Hashtable containers = new Hashtable();
|
||||
static EventQueue q;
|
||||
static Thread mainThread;
|
||||
private static EventQueue q;
|
||||
|
||||
static native void gtkInit(int portableNativeSync);
|
||||
|
||||
static native void gtkMain();
|
||||
|
||||
static native void gtkQuit();
|
||||
|
||||
static
|
||||
{
|
||||
System.loadLibrary("gtkpeer");
|
||||
|
||||
|
||||
int portableNativeSync;
|
||||
String portNatSyncProp =
|
||||
System.getProperty("gnu.classpath.awt.gtk.portable.native.sync");
|
||||
|
||||
|
||||
if (portNatSyncProp == null)
|
||||
portableNativeSync = -1; // unset
|
||||
else if (Boolean.valueOf(portNatSyncProp).booleanValue())
|
||||
portableNativeSync = 1; // true
|
||||
else
|
||||
portableNativeSync = 0; // false
|
||||
|
||||
|
||||
gtkInit(portableNativeSync);
|
||||
|
||||
mainThread = new Thread ("GTK main thread")
|
||||
{
|
||||
public void run ()
|
||||
{
|
||||
gtkMain ();
|
||||
}
|
||||
};
|
||||
mainThread.start ();
|
||||
}
|
||||
|
||||
public GtkToolkit ()
|
||||
@@ -169,6 +163,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
}
|
||||
|
||||
public native void beep();
|
||||
|
||||
private native void getScreenSizeDimensions(int[] xy);
|
||||
|
||||
public int checkImage (Image image, int width, int height,
|
||||
@@ -181,6 +176,9 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
if (image instanceof GtkImage)
|
||||
return ((GtkImage) image).checkImage (observer);
|
||||
|
||||
if (image instanceof AsyncImage)
|
||||
return ((AsyncImage) image).checkImage(observer);
|
||||
|
||||
if (observer != null)
|
||||
observer.imageUpdate (image, status,
|
||||
-1, -1,
|
||||
@@ -194,7 +192,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
* Helper to return either a Image -- the argument -- or a
|
||||
* GtkImage with the errorLoading flag set if the argument is null.
|
||||
*/
|
||||
private Image imageOrError(Image b)
|
||||
static Image imageOrError(Image b)
|
||||
{
|
||||
if (b == null)
|
||||
return GtkImage.getErrorImage();
|
||||
@@ -221,16 +219,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
|
||||
public Image createImage (URL url)
|
||||
{
|
||||
Image image;
|
||||
try
|
||||
{
|
||||
image = CairoSurface.getBufferedImage( new GtkImage( url ) );
|
||||
}
|
||||
catch (IllegalArgumentException iae)
|
||||
{
|
||||
image = null;
|
||||
}
|
||||
return imageOrError(image);
|
||||
return new AsyncImage(url);
|
||||
}
|
||||
|
||||
public Image createImage (ImageProducer producer)
|
||||
@@ -301,7 +290,7 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
"SansSerif" });
|
||||
}
|
||||
|
||||
private class LRUCache extends LinkedHashMap
|
||||
static class LRUCache extends LinkedHashMap
|
||||
{
|
||||
int max_entries;
|
||||
public LRUCache(int max)
|
||||
@@ -316,23 +305,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
}
|
||||
|
||||
private LRUCache fontCache = new LRUCache(50);
|
||||
private LRUCache metricsCache = new LRUCache(50);
|
||||
private LRUCache imageCache = new LRUCache(50);
|
||||
|
||||
public FontMetrics getFontMetrics (Font font)
|
||||
{
|
||||
synchronized (metricsCache)
|
||||
{
|
||||
if (metricsCache.containsKey(font))
|
||||
return (FontMetrics) metricsCache.get(font);
|
||||
}
|
||||
|
||||
FontMetrics m = new GdkFontMetrics (font);
|
||||
synchronized (metricsCache)
|
||||
{
|
||||
metricsCache.put(font, m);
|
||||
}
|
||||
return m;
|
||||
return ((GdkFontPeer) font.getPeer()).getFontMetrics(font);
|
||||
}
|
||||
|
||||
public Image getImage (String filename)
|
||||
@@ -408,6 +385,13 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
return ((((GtkImage)image).checkImage (observer) &
|
||||
ImageObserver.ALLBITS) != 0);
|
||||
|
||||
if (image instanceof AsyncImage)
|
||||
{
|
||||
AsyncImage aImg = (AsyncImage) image;
|
||||
aImg.addObserver(observer);
|
||||
return aImg.realImage != null;
|
||||
}
|
||||
|
||||
/* Assume anything else is too */
|
||||
return true;
|
||||
}
|
||||
@@ -437,106 +421,131 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
|
||||
protected ButtonPeer createButton (Button b)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkButtonPeer (b);
|
||||
}
|
||||
|
||||
protected CanvasPeer createCanvas (Canvas c)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkCanvasPeer (c);
|
||||
}
|
||||
|
||||
protected CheckboxPeer createCheckbox (Checkbox cb)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkCheckboxPeer (cb);
|
||||
}
|
||||
|
||||
protected CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem cmi)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkCheckboxMenuItemPeer (cmi);
|
||||
}
|
||||
|
||||
protected ChoicePeer createChoice (Choice c)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkChoicePeer (c);
|
||||
}
|
||||
|
||||
protected DialogPeer createDialog (Dialog d)
|
||||
{
|
||||
checkHeadless();
|
||||
GtkMainThread.createWindow();
|
||||
return new GtkDialogPeer (d);
|
||||
}
|
||||
|
||||
protected FileDialogPeer createFileDialog (FileDialog fd)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkFileDialogPeer (fd);
|
||||
}
|
||||
|
||||
protected FramePeer createFrame (Frame f)
|
||||
{
|
||||
checkHeadless();
|
||||
GtkMainThread.createWindow();
|
||||
return new GtkFramePeer (f);
|
||||
}
|
||||
|
||||
protected LabelPeer createLabel (Label label)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkLabelPeer (label);
|
||||
}
|
||||
|
||||
protected ListPeer createList (List list)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkListPeer (list);
|
||||
}
|
||||
|
||||
protected MenuPeer createMenu (Menu m)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkMenuPeer (m);
|
||||
}
|
||||
|
||||
protected MenuBarPeer createMenuBar (MenuBar mb)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkMenuBarPeer (mb);
|
||||
}
|
||||
|
||||
protected MenuItemPeer createMenuItem (MenuItem mi)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkMenuItemPeer (mi);
|
||||
}
|
||||
|
||||
protected PanelPeer createPanel (Panel p)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkPanelPeer (p);
|
||||
}
|
||||
|
||||
protected PopupMenuPeer createPopupMenu (PopupMenu target)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkPopupMenuPeer (target);
|
||||
}
|
||||
|
||||
protected ScrollPanePeer createScrollPane (ScrollPane sp)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkScrollPanePeer (sp);
|
||||
}
|
||||
|
||||
protected ScrollbarPeer createScrollbar (Scrollbar sb)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkScrollbarPeer (sb);
|
||||
}
|
||||
|
||||
protected TextAreaPeer createTextArea (TextArea ta)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkTextAreaPeer (ta);
|
||||
}
|
||||
|
||||
protected TextFieldPeer createTextField (TextField tf)
|
||||
{
|
||||
checkHeadless();
|
||||
return new GtkTextFieldPeer (tf);
|
||||
}
|
||||
|
||||
protected WindowPeer createWindow (Window w)
|
||||
{
|
||||
checkHeadless();
|
||||
GtkMainThread.createWindow();
|
||||
return new GtkWindowPeer (w);
|
||||
}
|
||||
|
||||
public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w)
|
||||
{
|
||||
checkHeadless();
|
||||
GtkMainThread.createWindow();
|
||||
return new GtkEmbeddedWindowPeer (w);
|
||||
}
|
||||
|
||||
@@ -605,6 +614,8 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
|
||||
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
|
||||
{
|
||||
if (GraphicsEnvironment.isHeadless())
|
||||
throw new InvalidDnDOperationException();
|
||||
return new GtkDragSourceContextPeer(e);
|
||||
}
|
||||
|
||||
@@ -614,7 +625,8 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
int actions,
|
||||
DragGestureListener l)
|
||||
{
|
||||
if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer"))
|
||||
if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer")
|
||||
&& ! GraphicsEnvironment.isHeadless())
|
||||
{
|
||||
GtkMouseDragGestureRecognizer gestureRecognizer
|
||||
= new GtkMouseDragGestureRecognizer(ds, comp, actions, l);
|
||||
@@ -661,13 +673,25 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit
|
||||
GdkPixbufDecoder.registerSpis(reg);
|
||||
}
|
||||
|
||||
public static native void gtkMain();
|
||||
|
||||
protected MouseInfoPeer getMouseInfoPeer()
|
||||
{
|
||||
return new GtkMouseInfoPeer();
|
||||
}
|
||||
|
||||
public boolean isFrameStateSupported(int state)
|
||||
{
|
||||
// GTK supports ICONFIED, NORMAL and MAXIMIZE_BOTH, but
|
||||
// not (yet?) MAXIMIZE_VERT and MAXIMIZE_HORIZ.
|
||||
return state == Frame.NORMAL || state == Frame.ICONIFIED
|
||||
|| state == Frame.MAXIMIZED_BOTH;
|
||||
}
|
||||
|
||||
private void checkHeadless()
|
||||
{
|
||||
if (GraphicsEnvironment.isHeadless())
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public native int getMouseNumberOfButtons();
|
||||
|
||||
} // class GtkToolkit
|
||||
|
||||
@@ -37,13 +37,21 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.ImageCapabilities;
|
||||
import java.awt.Point;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.SinglePixelPackedSampleModel;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
public class GtkVolatileImage extends VolatileImage
|
||||
{
|
||||
@@ -52,6 +60,12 @@ public class GtkVolatileImage extends VolatileImage
|
||||
|
||||
final GtkComponentPeer component;
|
||||
|
||||
static ColorModel gdkColorModel = new DirectColorModel(32,
|
||||
0x000000FF,
|
||||
0x0000FF00,
|
||||
0x00FF0000,
|
||||
0xFF000000);
|
||||
|
||||
/**
|
||||
* Don't touch, accessed from native code.
|
||||
*/
|
||||
@@ -62,6 +76,17 @@ public class GtkVolatileImage extends VolatileImage
|
||||
native void destroy(long pointer);
|
||||
|
||||
native int[] nativeGetPixels(long pointer);
|
||||
|
||||
/**
|
||||
* Gets the pixels in the current image from GDK.
|
||||
*
|
||||
* Note that pixels are in 32-bit RGBA, non-premultiplied, which is different
|
||||
* from Cairo's premultiplied ARGB, which is different from Java's standard
|
||||
* non-premultiplied ARGB. Caution is advised when using this method, to
|
||||
* ensure that the data format remains consistent with what you expect.
|
||||
*
|
||||
* @return the current pixels, as reported by GDK.
|
||||
*/
|
||||
public int[] getPixels()
|
||||
{
|
||||
return nativeGetPixels(nativePointer);
|
||||
@@ -113,9 +138,11 @@ public class GtkVolatileImage extends VolatileImage
|
||||
|
||||
public BufferedImage getSnapshot()
|
||||
{
|
||||
CairoSurface cs = new CairoSurface( width, height );
|
||||
cs.setPixels( getPixels() );
|
||||
return CairoSurface.getBufferedImage( cs );
|
||||
WritableRaster raster = Raster.createWritableRaster(createGdkSampleModel(width, height),
|
||||
new Point(0, 0));
|
||||
raster.setDataElements(0, 0, getPixels());
|
||||
return new BufferedImage(gdkColorModel, raster,
|
||||
gdkColorModel.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
public Graphics getGraphics()
|
||||
@@ -167,4 +194,14 @@ public class GtkVolatileImage extends VolatileImage
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SampleModel that matches GDK's native format
|
||||
*/
|
||||
protected static SampleModel createGdkSampleModel(int w, int h)
|
||||
{
|
||||
return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h,
|
||||
new int[]{0x000000FF, 0x0000FF00,
|
||||
0x00FF0000, 0xFF000000});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,10 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.gtk;
|
||||
|
||||
import gnu.java.awt.ComponentReshapeEvent;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
@@ -62,8 +65,7 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6;
|
||||
protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7;
|
||||
|
||||
private boolean hasBeenShown = false;
|
||||
private int oldState = Frame.NORMAL;
|
||||
protected int windowState = Frame.NORMAL;
|
||||
|
||||
// Cached awt window component location, width and height.
|
||||
private int x, y, width, height;
|
||||
@@ -75,6 +77,12 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
native boolean gtkWindowHasFocus();
|
||||
native void realize ();
|
||||
|
||||
public void dispose()
|
||||
{
|
||||
super.dispose();
|
||||
GtkMainThread.destroyWindow();
|
||||
}
|
||||
|
||||
/** Returns the cached width of the AWT window component. */
|
||||
int getX ()
|
||||
{
|
||||
@@ -144,6 +152,8 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
public GtkWindowPeer (Window window)
|
||||
{
|
||||
super (window);
|
||||
// Set reasonable font for the window.
|
||||
window.setFont(new Font("Dialog", Font.PLAIN, 12));
|
||||
}
|
||||
|
||||
public native void toBack();
|
||||
@@ -218,9 +228,31 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
// only called from GTK thread
|
||||
protected void postConfigureEvent (int x, int y, int width, int height)
|
||||
{
|
||||
int frame_x = x - insets.left;
|
||||
int frame_y = y - insets.top;
|
||||
int frame_width = width + insets.left + insets.right;
|
||||
int frame_height = height + insets.top + insets.bottom;
|
||||
|
||||
// Update the component's knowledge about the size.
|
||||
// Important: Please look at the big comment in ComponentReshapeEvent
|
||||
// to learn why we did it this way. If you change this code, make
|
||||
// sure that the peer->AWT bounds update still works.
|
||||
// (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 )
|
||||
|
||||
// We do this befor we post the ComponentEvent, because (in Window)
|
||||
// we invalidate() / revalidate() when a ComponentEvent is seen,
|
||||
// and the AWT must already know about the new size then.
|
||||
if (frame_x != this.x || frame_y != this.y || frame_width != this.width
|
||||
|| frame_height != this.height)
|
||||
{
|
||||
ComponentReshapeEvent ev = new ComponentReshapeEvent(awtComponent,
|
||||
frame_x,
|
||||
frame_y,
|
||||
frame_width,
|
||||
frame_height);
|
||||
awtComponent.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
if (frame_width != getWidth()
|
||||
|| frame_height != getHeight())
|
||||
{
|
||||
@@ -230,9 +262,6 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
ComponentEvent.COMPONENT_RESIZED));
|
||||
}
|
||||
|
||||
int frame_x = x - insets.left;
|
||||
int frame_y = y - insets.top;
|
||||
|
||||
if (frame_x != getX()
|
||||
|| frame_y != getY())
|
||||
{
|
||||
@@ -241,6 +270,7 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
q().postEvent(new ComponentEvent(awtComponent,
|
||||
ComponentEvent.COMPONENT_MOVED));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void show ()
|
||||
@@ -255,23 +285,26 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
|
||||
void postWindowEvent (int id, Window opposite, int newState)
|
||||
{
|
||||
if (id == WindowEvent.WINDOW_OPENED)
|
||||
if (id == WindowEvent.WINDOW_STATE_CHANGED)
|
||||
{
|
||||
// Post a WINDOW_OPENED event the first time this window is shown.
|
||||
if (!hasBeenShown)
|
||||
if (windowState != newState)
|
||||
{
|
||||
// Post old styleWindowEvent with WINDOW_ICONIFIED or
|
||||
// WINDOW_DEICONIFIED if appropriate.
|
||||
if ((windowState & Frame.ICONIFIED) != 0
|
||||
&& (newState & Frame.ICONIFIED) == 0)
|
||||
q().postEvent(new WindowEvent((Window) awtComponent,
|
||||
WindowEvent.WINDOW_DEICONIFIED,
|
||||
opposite, 0, 0));
|
||||
else if ((windowState & Frame.ICONIFIED) == 0
|
||||
&& (newState & Frame.ICONIFIED) != 0)
|
||||
q().postEvent(new WindowEvent((Window) awtComponent,
|
||||
WindowEvent.WINDOW_ICONIFIED,
|
||||
opposite, 0, 0));
|
||||
// Post new-style WindowStateEvent.
|
||||
q().postEvent (new WindowEvent ((Window) awtComponent, id,
|
||||
opposite));
|
||||
hasBeenShown = true;
|
||||
}
|
||||
}
|
||||
else if (id == WindowEvent.WINDOW_STATE_CHANGED)
|
||||
{
|
||||
if (oldState != newState)
|
||||
{
|
||||
q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite,
|
||||
oldState, newState));
|
||||
oldState = newState;
|
||||
opposite, windowState, newState));
|
||||
windowState = newState;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -350,13 +383,6 @@ public class GtkWindowPeer extends GtkContainerPeer
|
||||
return g;
|
||||
}
|
||||
|
||||
protected void updateComponent (PaintEvent event)
|
||||
{
|
||||
// Do not clear anything before painting. Sun never calls
|
||||
// Window.update, only Window.paint.
|
||||
paintComponent(event);
|
||||
}
|
||||
|
||||
protected void postMouseEvent(int id, long when, int mods, int x, int y,
|
||||
int clickCount, boolean popupTrigger)
|
||||
{
|
||||
|
||||
@@ -38,15 +38,32 @@ exception statement from your version. */
|
||||
|
||||
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;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
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;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class VolatileImageGraphics extends ComponentGraphics
|
||||
{
|
||||
private GtkVolatileImage owner;
|
||||
private BufferedImage buffer;
|
||||
|
||||
public VolatileImageGraphics(GtkVolatileImage img)
|
||||
{
|
||||
@@ -77,10 +94,118 @@ public class VolatileImageGraphics extends ComponentGraphics
|
||||
return new VolatileImageGraphics( this );
|
||||
}
|
||||
|
||||
public void draw(Shape s)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.draw(s);
|
||||
|
||||
// Custom composite
|
||||
else
|
||||
{
|
||||
// Draw operation to temporary buffer
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setColor(this.getColor());
|
||||
g2d.setStroke(this.getStroke());
|
||||
g2d.draw(s);
|
||||
|
||||
drawComposite(s.getBounds2D(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(Shape s)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.fill(s);
|
||||
|
||||
// Custom composite
|
||||
else
|
||||
{
|
||||
// Draw operation to temporary buffer
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
g2d.setPaint(this.getPaint());
|
||||
g2d.setColor(this.getColor());
|
||||
g2d.fill(s);
|
||||
|
||||
drawComposite(s.getBounds2D(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawGlyphVector(GlyphVector gv, float x, float y)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
super.drawGlyphVector(gv, x, y);
|
||||
|
||||
// Custom composite
|
||||
else
|
||||
{
|
||||
// Draw operation to temporary buffer
|
||||
createBuffer();
|
||||
|
||||
Graphics2D g2d = (Graphics2D)buffer.getGraphics();
|
||||
|
||||
g2d.setPaint(this.getPaint());
|
||||
g2d.setColor(this.getColor());
|
||||
g2d.drawGlyphVector(gv, x, y);
|
||||
|
||||
Rectangle2D bounds = gv.getLogicalBounds();
|
||||
bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
|
||||
bounds.getWidth(), bounds.getHeight());
|
||||
drawComposite(bounds, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean drawImage(Image img, AffineTransform xform,
|
||||
Color bgcolor, ImageObserver obs)
|
||||
{
|
||||
if (comp == null || comp instanceof AlphaComposite)
|
||||
return super.drawImage(img, xform, bgcolor, obs);
|
||||
|
||||
// Custom composite
|
||||
else
|
||||
{
|
||||
// Get buffered image of source
|
||||
if( !(img instanceof BufferedImage) )
|
||||
{
|
||||
ImageProducer source = img.getSource();
|
||||
if (source == null)
|
||||
return false;
|
||||
img = Toolkit.getDefaultToolkit().createImage(source);
|
||||
}
|
||||
BufferedImage bImg = (BufferedImage) img;
|
||||
|
||||
// Find dimensions of translation
|
||||
Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
|
||||
Point2D pt = new Point2D.Double(bImg.getWidth(), bImg.getHeight());
|
||||
if (xform != null)
|
||||
{
|
||||
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 from buffer to screen
|
||||
return drawComposite(new Rectangle2D.Double((int)origin.getX(),
|
||||
(int)origin.getY(),
|
||||
(int)pt.getX(),
|
||||
(int)pt.getY()),
|
||||
obs);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean drawImage(Image img, int x, int y, ImageObserver observer)
|
||||
{
|
||||
if( img instanceof GtkVolatileImage )
|
||||
if (img instanceof GtkVolatileImage
|
||||
&& (comp == null || comp instanceof AlphaComposite))
|
||||
{
|
||||
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
|
||||
x, y,
|
||||
@@ -94,7 +219,8 @@ public class VolatileImageGraphics extends ComponentGraphics
|
||||
public boolean drawImage(Image img, int x, int y, int width, int height,
|
||||
ImageObserver observer)
|
||||
{
|
||||
if( img instanceof GtkVolatileImage )
|
||||
if ((img instanceof GtkVolatileImage)
|
||||
&& (comp == null || comp instanceof AlphaComposite))
|
||||
{
|
||||
owner.drawVolatile( ((GtkVolatileImage)img).nativePointer,
|
||||
x, y, width, height );
|
||||
@@ -107,5 +233,84 @@ public class VolatileImageGraphics extends ComponentGraphics
|
||||
{
|
||||
return new Rectangle2D.Double(0, 0, owner.width, owner.height);
|
||||
}
|
||||
|
||||
private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
|
||||
{
|
||||
// Clip source to visible areas that need updating
|
||||
Rectangle2D clip = this.getClipBounds();
|
||||
Rectangle2D.intersect(bounds, clip, bounds);
|
||||
|
||||
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 current on-screen pixels (destination) and clip to bounds
|
||||
BufferedImage current = owner.getSnapshot();
|
||||
|
||||
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);
|
||||
|
||||
current = current.getSubimage((int)deviceBounds.getX(),
|
||||
(int)deviceBounds.getY(),
|
||||
(int)deviceBounds.getWidth(),
|
||||
(int)deviceBounds.getHeight());
|
||||
|
||||
// Perform actual composite operation
|
||||
compCtx.compose(buffer2.getRaster(), current.getRaster(),
|
||||
buffer2.getRaster());
|
||||
|
||||
// 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!
|
||||
Composite oldComp = comp; // so that ComponentGraphics doesn't
|
||||
comp = null; // process the composite again
|
||||
boolean rv = super.drawImage(buffer2,
|
||||
AffineTransform.getTranslateInstance(bounds.getX(),
|
||||
bounds.getY()),
|
||||
null, null);
|
||||
comp = oldComp;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void createBuffer()
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
WritableRaster rst;
|
||||
rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(owner.width,
|
||||
owner.height),
|
||||
new Point(0,0));
|
||||
|
||||
buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
|
||||
GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
|
||||
new Hashtable());
|
||||
}
|
||||
else
|
||||
{
|
||||
Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
|
||||
|
||||
g2d.setBackground(new Color(0,0,0,0));
|
||||
g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
protected ColorModel getNativeCM()
|
||||
{
|
||||
// We should really return GtkVolatileImage.gdkColorModel ,
|
||||
// but CairoGraphics2D doesn't handle alpha premultiplication properly (see
|
||||
// the fixme in drawImage) so we use the naive Cairo model instead to trick
|
||||
// the compositing context.
|
||||
// Because getNativeCM() == getBufferCM() for this peer, it doesn't break.
|
||||
return CairoSurface.cairoCM_pre;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/* HeadlessGraphicsEnvironment.java -- A graphics environment for headless mode
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.peer.headless;
|
||||
|
||||
import gnu.java.awt.java2d.RasterGraphics;
|
||||
|
||||
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.Raster;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Locale;
|
||||
|
||||
public class HeadlessGraphicsEnvironment
|
||||
extends GraphicsEnvironment
|
||||
{
|
||||
|
||||
public Graphics2D createGraphics(BufferedImage image)
|
||||
{
|
||||
Graphics2D g2d;
|
||||
try
|
||||
{
|
||||
// Try to get a CairoGraphics (accellerated) when available. Do this
|
||||
// via reflection to avoid having a hard compile time dependency.
|
||||
Class cairoSurfaceCl =
|
||||
Class.forName("gnu.java.awt.peer.gtk.CairoSurface");
|
||||
Raster raster = image.getRaster();
|
||||
if (cairoSurfaceCl.isInstance(raster))
|
||||
{
|
||||
Method getGraphicsM = cairoSurfaceCl.getMethod("getGraphics",
|
||||
new Class[0]);
|
||||
g2d = (Graphics2D) getGraphicsM.invoke(raster, new Object[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Class bigCl =
|
||||
Class.forName("gnu.java.awt.peer.gtk.BufferedImageGraphics");
|
||||
Constructor bigC =
|
||||
bigCl.getConstructor(new Class[]{BufferedImage.class });
|
||||
g2d = (Graphics2D) bigC.newInstance(new Object[]{ image});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
g2d = new RasterGraphics(image.getRaster(), image.getColorModel());
|
||||
}
|
||||
return g2d;
|
||||
}
|
||||
|
||||
public Font[] getAllFonts()
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getAvailableFontFamilyNames()
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getAvailableFontFamilyNames(Locale l)
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return null;
|
||||
}
|
||||
|
||||
public GraphicsDevice getDefaultScreenDevice()
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public GraphicsDevice[] getScreenDevices()
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
/* HeadlessToolkit.java -- A toolkit for headless mode
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
|
||||
package gnu.java.awt.peer.headless;
|
||||
|
||||
import gnu.java.awt.ClasspathToolkit;
|
||||
import gnu.java.awt.EmbeddedWindow;
|
||||
import gnu.java.awt.peer.ClasspathFontPeer;
|
||||
import gnu.java.awt.peer.EmbeddedWindowPeer;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Button;
|
||||
import java.awt.Canvas;
|
||||
import java.awt.Checkbox;
|
||||
import java.awt.CheckboxMenuItem;
|
||||
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.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.Label;
|
||||
import java.awt.List;
|
||||
import java.awt.Menu;
|
||||
import java.awt.MenuBar;
|
||||
import java.awt.MenuItem;
|
||||
import java.awt.Panel;
|
||||
import java.awt.PopupMenu;
|
||||
import java.awt.PrintJob;
|
||||
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.im.InputMethodHighlight;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.ImageProducer;
|
||||
import java.awt.peer.ButtonPeer;
|
||||
import java.awt.peer.CanvasPeer;
|
||||
import java.awt.peer.CheckboxMenuItemPeer;
|
||||
import java.awt.peer.CheckboxPeer;
|
||||
import java.awt.peer.ChoicePeer;
|
||||
import java.awt.peer.DialogPeer;
|
||||
import java.awt.peer.FileDialogPeer;
|
||||
import java.awt.peer.FontPeer;
|
||||
import java.awt.peer.FramePeer;
|
||||
import java.awt.peer.LabelPeer;
|
||||
import java.awt.peer.ListPeer;
|
||||
import java.awt.peer.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;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class HeadlessToolkit
|
||||
extends ClasspathToolkit
|
||||
{
|
||||
|
||||
/**
|
||||
* The graphics environment for headless graphics.
|
||||
*/
|
||||
private HeadlessGraphicsEnvironment graphicsEnv;
|
||||
|
||||
public void beep()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public int checkImage(Image image, int width, int height,
|
||||
ImageObserver observer)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected ButtonPeer createButton(Button target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected CanvasPeer createCanvas(Canvas target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected CheckboxPeer createCheckbox(Checkbox target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected ChoicePeer createChoice(Choice target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected DialogPeer createDialog(Dialog target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected FileDialogPeer createFileDialog(FileDialog target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected FramePeer createFrame(Frame target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public Image createImage(String filename)
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image createImage(URL url)
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image createImage(ImageProducer producer)
|
||||
{
|
||||
// FIXME: Implement.
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image createImage(byte[] data, int offset, int len)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
protected LabelPeer createLabel(Label target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected ListPeer createList(List target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected MenuPeer createMenu(Menu target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected MenuBarPeer createMenuBar(MenuBar target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected MenuItemPeer createMenuItem(MenuItem target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected PanelPeer createPanel(Panel target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected PopupMenuPeer createPopupMenu(PopupMenu target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected ScrollPanePeer createScrollPane(ScrollPane target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected ScrollbarPeer createScrollbar(Scrollbar target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected TextAreaPeer createTextArea(TextArea target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected TextFieldPeer createTextField(TextField target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected WindowPeer createWindow(Window target)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public ColorModel getColorModel()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getFontList()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public FontMetrics getFontMetrics(Font name)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
protected FontPeer getFontPeer(String name, int style)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image getImage(String name)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Image getImage(URL url)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public PrintJob getPrintJob(Frame frame, String title, Properties props)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getScreenResolution()
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public Dimension getScreenSize()
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public Clipboard getSystemClipboard()
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
protected EventQueue getSystemEventQueueImpl()
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public Map mapInputMethodHighlight(InputMethodHighlight highlight)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean prepareImage(Image image, int width, int height,
|
||||
ImageObserver observer)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sync()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w)
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public Font createFont(int format, InputStream stream)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public RobotPeer createRobot(GraphicsDevice screen) throws AWTException
|
||||
{
|
||||
throw new HeadlessException();
|
||||
}
|
||||
|
||||
public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public GraphicsEnvironment getLocalGraphicsEnvironment()
|
||||
{
|
||||
if (graphicsEnv == null)
|
||||
graphicsEnv = new HeadlessGraphicsEnvironment();
|
||||
return graphicsEnv;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -194,15 +194,4 @@ public class QtFontPeer extends ClasspathFontPeer
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Rectangle2D getStringBounds (Font font,
|
||||
CharacterIterator ci,
|
||||
int begin, int limit,
|
||||
FontRenderContext frc)
|
||||
{
|
||||
int index = begin;
|
||||
String s = "" + ci.setIndex( index );
|
||||
while( index++ <= limit )
|
||||
s = s + ci.next();
|
||||
return metrics.getStringBounds(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,12 +669,13 @@ public abstract class QtGraphics extends Graphics2D
|
||||
|
||||
public RenderingHints getRenderingHints()
|
||||
{
|
||||
return new RenderingHints( renderingHints );
|
||||
return (RenderingHints) renderingHints.clone();
|
||||
}
|
||||
|
||||
public void setRenderingHints(Map hints)
|
||||
public void setRenderingHints(Map<?,?> hints)
|
||||
{
|
||||
renderingHints = new RenderingHints( hints );
|
||||
renderingHints = new RenderingHints( null );
|
||||
renderingHints.putAll(hints);
|
||||
updateRenderingHints();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Button;
|
||||
import java.awt.Container;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
@@ -69,6 +70,13 @@ public class SwingButtonPeer
|
||||
extends JButton
|
||||
implements SwingComponent
|
||||
{
|
||||
Button button;
|
||||
|
||||
SwingButton(Button button)
|
||||
{
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden so that this method returns the correct value even without a
|
||||
* peer.
|
||||
@@ -90,8 +98,8 @@ public class SwingButtonPeer
|
||||
public boolean isShowing()
|
||||
{
|
||||
boolean retVal = false;
|
||||
if (SwingButtonPeer.this.awtComponent != null)
|
||||
retVal = SwingButtonPeer.this.awtComponent.isShowing();
|
||||
if (button != null)
|
||||
retVal = button.isShowing();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -168,6 +176,14 @@ public class SwingButtonPeer
|
||||
ev.setSource(this);
|
||||
processKeyEvent(ev);
|
||||
}
|
||||
|
||||
public Container getParent()
|
||||
{
|
||||
Container par = null;
|
||||
if (button != null)
|
||||
par = button.getParent();
|
||||
return par;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,7 +221,7 @@ public class SwingButtonPeer
|
||||
*/
|
||||
public SwingButtonPeer(Button theButton)
|
||||
{
|
||||
SwingButton button = new SwingButton();
|
||||
SwingButton button = new SwingButton(theButton);
|
||||
button.setText(theButton.getLabel());
|
||||
button.addActionListener(new SwingButtonListener());
|
||||
init(theButton, button);
|
||||
|
||||
@@ -62,7 +62,7 @@ public interface SwingComponent
|
||||
|
||||
/**
|
||||
* Handles a mouse event. This is usually forwarded to
|
||||
* {@link java.awt.Component#processMouseMotionEvent(MouseEvent)} of the swing
|
||||
* {@link Component#processMouseMotionEvent(MouseEvent)} of the swing
|
||||
* component.
|
||||
*
|
||||
* @param ev the mouse event
|
||||
@@ -71,7 +71,7 @@ public interface SwingComponent
|
||||
|
||||
/**
|
||||
* Handles a mouse motion event. This is usually forwarded to
|
||||
* {@link java.awt.Component#processMouseEvent(MouseEvent)} of the swing
|
||||
* {@link Component#processMouseEvent(MouseEvent)} of the swing
|
||||
* component.
|
||||
*
|
||||
* @param ev the mouse motion event
|
||||
@@ -80,7 +80,7 @@ public interface SwingComponent
|
||||
|
||||
/**
|
||||
* Handles a key event. This is usually forwarded to
|
||||
* {@link java.awt.Component#processKeyEvent(KeyEvent)} of the swing
|
||||
* {@link Component#processKeyEvent(KeyEvent)} of the swing
|
||||
* component.
|
||||
*
|
||||
* @param ev the key event
|
||||
|
||||
@@ -42,6 +42,7 @@ import java.awt.AWTException;
|
||||
import java.awt.BufferCapabilities;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
@@ -62,6 +63,10 @@ import java.awt.image.ImageProducer;
|
||||
import java.awt.image.VolatileImage;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.ContainerPeer;
|
||||
import java.awt.peer.LightweightPeer;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.RepaintManager;
|
||||
|
||||
/**
|
||||
* The base class for Swing based component peers. This provides the basic
|
||||
@@ -97,9 +102,18 @@ public class SwingComponentPeer
|
||||
protected SwingComponent swingComponent;
|
||||
|
||||
/**
|
||||
* The font that is set for this peer.
|
||||
*/
|
||||
protected Font peerFont;
|
||||
|
||||
/**
|
||||
* The current repaint area.
|
||||
*/
|
||||
protected Rectangle paintArea;
|
||||
|
||||
/**
|
||||
* Creates a SwingComponentPeer instance. Subclasses are expected to call
|
||||
* this constructor and thereafter call
|
||||
* {@link #init(Component,SwingComponent)}
|
||||
* this constructor and thereafter call {@link #init(Component, JComponent)}
|
||||
* in order to setup the AWT and Swing components properly.
|
||||
*/
|
||||
protected SwingComponentPeer()
|
||||
@@ -118,6 +132,38 @@ public class SwingComponentPeer
|
||||
{
|
||||
awtComponent = awtComp;
|
||||
swingComponent = swingComp;
|
||||
if (swingComponent != null)
|
||||
{
|
||||
JComponent c = swingComponent.getJComponent();
|
||||
if (c != null)
|
||||
{
|
||||
c.addNotify();
|
||||
RepaintManager.currentManager(c).setDoubleBufferingEnabled(false);
|
||||
System.setProperty("gnu.awt.swing.doublebuffering", "true");
|
||||
}
|
||||
}
|
||||
|
||||
// Register this heavyweight component with the nearest heavyweight
|
||||
// container, so we get peerPaint() triggered by that container.
|
||||
if (! (this instanceof LightweightPeer))
|
||||
{
|
||||
Component comp = awtComponent;
|
||||
Container parent = comp.getParent();
|
||||
while (parent != null &&
|
||||
! (parent.getPeer() instanceof SwingContainerPeer))
|
||||
{
|
||||
comp = parent;
|
||||
parent = comp.getParent();
|
||||
}
|
||||
|
||||
// At this point we have the ancestor with a SwingContainerPeer
|
||||
// (or null peer).
|
||||
if (parent != null && parent.getPeer() instanceof SwingContainerPeer)
|
||||
{
|
||||
SwingContainerPeer p = (SwingContainerPeer) parent.getPeer();
|
||||
p.addHeavyweightDescendent(awtComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,6 +231,28 @@ public class SwingComponentPeer
|
||||
*/
|
||||
public void dispose()
|
||||
{
|
||||
// Unregister this heavyweight component from the nearest heavyweight
|
||||
// container.
|
||||
if (! (this instanceof LightweightPeer))
|
||||
{
|
||||
Component comp = awtComponent;
|
||||
Container parent = comp.getParent();
|
||||
while (parent != null &&
|
||||
! (parent.getPeer() instanceof SwingContainerPeer))
|
||||
{
|
||||
comp = parent;
|
||||
parent = comp.getParent();
|
||||
}
|
||||
|
||||
// At this point we have the ancestor with a SwingContainerPeer
|
||||
// (or null peer).
|
||||
if (parent != null && parent.getPeer() instanceof SwingContainerPeer)
|
||||
{
|
||||
SwingContainerPeer p = (SwingContainerPeer) parent.getPeer();
|
||||
p.removeHeavyweightDescendent(awtComponent);
|
||||
}
|
||||
}
|
||||
|
||||
awtComponent = null;
|
||||
swingComponent = null;
|
||||
}
|
||||
@@ -244,8 +312,7 @@ public class SwingComponentPeer
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
Component parent = awtComponent.getParent();
|
||||
ComponentPeer parentPeer = parent.getPeer();
|
||||
Graphics g = parentPeer.getGraphics();
|
||||
Graphics g = parent.getGraphics();
|
||||
g.translate(awtComponent.getX(), awtComponent.getY());
|
||||
g.setClip(0, 0, awtComponent.getWidth(), awtComponent.getHeight());
|
||||
return g;
|
||||
@@ -331,23 +398,28 @@ public class SwingComponentPeer
|
||||
{
|
||||
case PaintEvent.UPDATE:
|
||||
case PaintEvent.PAINT:
|
||||
// This only will work when the component is showing.
|
||||
if (awtComponent.isShowing())
|
||||
// Need to synchronize to avoid threading problems on the
|
||||
// paint event list.
|
||||
// We must synchronize on the tree lock first to avoid deadlock,
|
||||
// because Container.paint() will grab it anyway.
|
||||
synchronized (this)
|
||||
{
|
||||
Graphics g = getGraphics();
|
||||
Rectangle clip = ((PaintEvent)e).getUpdateRect();
|
||||
g.clipRect(clip.x, clip.y, clip.width, clip.height);
|
||||
//if (this instanceof LightweightPeer)
|
||||
// {
|
||||
if (e.getID() == PaintEvent.UPDATE)
|
||||
awtComponent.update(g);
|
||||
else
|
||||
awtComponent.paint(g);
|
||||
// }
|
||||
// We paint the 'heavyweights' at last, so that they appear on top of
|
||||
// everything else.
|
||||
peerPaint(g);
|
||||
g.dispose();
|
||||
assert paintArea != null;
|
||||
if (awtComponent.isShowing())
|
||||
{
|
||||
Graphics g = awtComponent.getGraphics();
|
||||
try
|
||||
{
|
||||
Rectangle clip = paintArea;
|
||||
g.clipRect(clip.x, clip.y, clip.width, clip.height);
|
||||
peerPaint(g, e.getID() == PaintEvent.UPDATE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
g.dispose();
|
||||
paintArea = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MouseEvent.MOUSE_PRESSED:
|
||||
@@ -451,9 +523,15 @@ public class SwingComponentPeer
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints the component. This is triggered by
|
||||
* {@link Component#paintAll(Graphics)}.
|
||||
*
|
||||
* @param graphics the graphics to paint with
|
||||
*/
|
||||
public void paint(Graphics graphics)
|
||||
{
|
||||
// FIXME: I don't know what this method is supposed to do.
|
||||
peerPaint(graphics, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -634,6 +712,7 @@ public class SwingComponentPeer
|
||||
*/
|
||||
public void setFont(Font font)
|
||||
{
|
||||
peerFont = font;
|
||||
if (swingComponent != null)
|
||||
swingComponent.getJComponent().setFont(font);
|
||||
}
|
||||
@@ -741,7 +820,14 @@ public class SwingComponentPeer
|
||||
*/
|
||||
public void coalescePaintEvent(PaintEvent e)
|
||||
{
|
||||
// Nothing to do here yet.
|
||||
synchronized (this)
|
||||
{
|
||||
Rectangle newRect = e.getUpdateRect();
|
||||
if (paintArea == null)
|
||||
paintArea = newRect;
|
||||
else
|
||||
Rectangle.union(paintArea, newRect, paintArea);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -947,9 +1033,33 @@ public class SwingComponentPeer
|
||||
* paint() on the Swing component.
|
||||
*
|
||||
* @param g the graphics context to use for painting
|
||||
* @param update wether we need to call update or paint on the AWT component
|
||||
*/
|
||||
protected void peerPaint(Graphics g)
|
||||
protected void peerPaint(Graphics g, boolean update)
|
||||
{
|
||||
peerPaintComponent(g);
|
||||
|
||||
Graphics userGraphics = g.create();
|
||||
try{
|
||||
if (update)
|
||||
awtComponent.update(userGraphics);
|
||||
else
|
||||
awtComponent.paint(userGraphics);
|
||||
} finally {
|
||||
userGraphics.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints the actual 'heavyweight' swing component, if there is one
|
||||
* associated to this peer.
|
||||
*
|
||||
* @param g the graphics to paint the component with
|
||||
*/
|
||||
protected void peerPaintComponent(Graphics g)
|
||||
{
|
||||
// Paint the actual Swing component if this peer has one.
|
||||
if (swingComponent != null)
|
||||
swingComponent.getJComponent().paint(g);
|
||||
}
|
||||
|
||||
@@ -37,14 +37,20 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import gnu.classpath.SystemProperties;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.ContainerPeer;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* A peer for Container to be used with the Swing based AWT peers.
|
||||
@@ -56,14 +62,54 @@ public class SwingContainerPeer
|
||||
implements ContainerPeer
|
||||
{
|
||||
|
||||
/**
|
||||
* Stores all heavyweight descendents of the container. This is used
|
||||
* in {@link #peerPaintChildren(Graphics)}.
|
||||
*/
|
||||
private LinkedList heavyweightDescendents;
|
||||
|
||||
/**
|
||||
* The backbuffer used for painting UPDATE events.
|
||||
*/
|
||||
private Image backbuffer;
|
||||
|
||||
/**
|
||||
* Creates a new SwingContainerPeer.
|
||||
*
|
||||
* @param awtCont
|
||||
*/
|
||||
public SwingContainerPeer(Component awtCont)
|
||||
public SwingContainerPeer(Container awtCont)
|
||||
{
|
||||
init(awtCont, null);
|
||||
heavyweightDescendents = new LinkedList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a heavyweight descendent. This is then painted by
|
||||
* {@link #peerPaintChildren(Graphics)}.
|
||||
*
|
||||
* @param comp the descendent to register
|
||||
*
|
||||
* @see #peerPaintChildren(Graphics)
|
||||
* @see #removeHeavyweightDescendent(Component)
|
||||
*/
|
||||
synchronized void addHeavyweightDescendent(Component comp)
|
||||
{
|
||||
heavyweightDescendents.add(comp);
|
||||
focusOwner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a heavyweight descendent.
|
||||
*
|
||||
* @param comp the descendent to unregister
|
||||
*
|
||||
* @see #peerPaintChildren(Graphics)
|
||||
* @see #addHeavyweightDescendent(Component)
|
||||
*/
|
||||
synchronized void removeHeavyweightDescendent(Component comp)
|
||||
{
|
||||
heavyweightDescendents.remove(comp);
|
||||
focusOwner = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,12 +138,7 @@ public class SwingContainerPeer
|
||||
*/
|
||||
public Insets getInsets()
|
||||
{
|
||||
Insets retVal;
|
||||
if (swingComponent != null)
|
||||
retVal = swingComponent.getJComponent().getInsets();
|
||||
else
|
||||
retVal = new Insets(0, 0, 0, 0);
|
||||
return retVal;
|
||||
return insets();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,38 +212,83 @@ public class SwingContainerPeer
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers painting of a component. This calls peerPaint on all the child
|
||||
* components of this container.
|
||||
*
|
||||
* @param g the graphics context to paint to
|
||||
* Performs the super behaviour (call peerPaintComponent() and
|
||||
* awtComponent.paint()), and forwards the paint request to the heavyweight
|
||||
* descendents of the container.
|
||||
*/
|
||||
protected void peerPaint(Graphics g)
|
||||
protected void peerPaint(Graphics g, boolean update)
|
||||
{
|
||||
Container c = (Container) awtComponent;
|
||||
Component[] children = c.getComponents();
|
||||
for (int i = children.length - 1; i >= 0; --i)
|
||||
if (isDoubleBuffering())
|
||||
{
|
||||
Component child = children[i];
|
||||
ComponentPeer peer = child.getPeer();
|
||||
boolean translated = false;
|
||||
boolean clipped = false;
|
||||
Shape oldClip = g.getClip();
|
||||
int width = awtComponent.getWidth();
|
||||
int height = awtComponent.getHeight();
|
||||
if (backbuffer == null
|
||||
|| backbuffer.getWidth(awtComponent) < width
|
||||
|| backbuffer.getHeight(awtComponent) < height)
|
||||
backbuffer = awtComponent.createImage(width, height);
|
||||
Graphics g2 = backbuffer.getGraphics();
|
||||
Rectangle clip = g.getClipRect();
|
||||
try
|
||||
{
|
||||
g.translate(child.getX(), child.getY());
|
||||
translated = true;
|
||||
g.setClip(0, 0, child.getWidth(), child.getHeight());
|
||||
clipped = true;
|
||||
if (peer instanceof SwingComponentPeer)
|
||||
((SwingComponentPeer) peer).peerPaint(g);
|
||||
}
|
||||
{
|
||||
g2.setClip(clip);
|
||||
super.peerPaint(g2, update);
|
||||
peerPaintChildren(g2);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (translated)
|
||||
g.translate(- child.getX(), - child.getY());
|
||||
if (clipped)
|
||||
g.setClip(oldClip);
|
||||
}
|
||||
{
|
||||
g2.dispose();
|
||||
}
|
||||
g.drawImage(backbuffer, 0, 0, awtComponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.peerPaint(g, update);
|
||||
peerPaintChildren(g);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if we should do double buffering or not.
|
||||
*
|
||||
* @return if we should do double buffering or not
|
||||
*/
|
||||
private boolean isDoubleBuffering()
|
||||
{
|
||||
Object prop =
|
||||
SystemProperties.getProperty("gnu.awt.swing.doublebuffering", "false");
|
||||
return prop.equals("true");
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints any heavyweight child components.
|
||||
*
|
||||
* @param g the graphics to use for painting
|
||||
*/
|
||||
protected synchronized void peerPaintChildren(Graphics g)
|
||||
{
|
||||
// TODO: Is this the right painting order?
|
||||
for (Iterator i = heavyweightDescendents.iterator(); i.hasNext();)
|
||||
{
|
||||
Component child = (Component) i.next();
|
||||
ComponentPeer peer = child.getPeer();
|
||||
|
||||
if (peer instanceof SwingComponentPeer && child.isVisible())
|
||||
{
|
||||
// TODO: The translation here doesn't work for deeper
|
||||
// nested children. Fix this!
|
||||
Graphics g2 = g.create(child.getX(), child.getY(),
|
||||
child.getWidth(), child.getHeight());
|
||||
try
|
||||
{
|
||||
// update() is only called for the topmost component if
|
||||
// necessary, all other components only get paint() called.
|
||||
((SwingComponentPeer) peer).peerPaint(g2, false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
g2.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,17 +300,13 @@ public class SwingContainerPeer
|
||||
protected void handleMouseEvent(MouseEvent ev)
|
||||
{
|
||||
Component comp = awtComponent.getComponentAt(ev.getPoint());
|
||||
if(comp == null)
|
||||
comp = awtComponent;
|
||||
if (comp != null)
|
||||
if(comp == null) comp = awtComponent;
|
||||
ComponentPeer peer = comp.getPeer();
|
||||
if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
|
||||
{
|
||||
ComponentPeer peer = comp.getPeer();
|
||||
if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer)
|
||||
{
|
||||
ev.translatePoint(comp.getX(), comp.getY());
|
||||
ev.setSource(comp);
|
||||
((SwingComponentPeer) peer).handleMouseEvent(ev);
|
||||
}
|
||||
ev.translatePoint(comp.getX(), comp.getY());
|
||||
ev.setSource(comp);
|
||||
((SwingComponentPeer) peer).handleMouseEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,4 +328,39 @@ public class SwingContainerPeer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles key events on the component. This is usually forwarded to the
|
||||
* SwingComponent's processKeyEvent() method.
|
||||
*
|
||||
* @param e the key event
|
||||
*/
|
||||
protected void handleKeyEvent(KeyEvent e)
|
||||
{
|
||||
Component owner = getFocusOwner();
|
||||
if(owner != null)
|
||||
owner.dispatchEvent(e);
|
||||
else
|
||||
super.handleKeyEvent(e);
|
||||
}
|
||||
|
||||
private Component focusOwner = null;
|
||||
|
||||
private Component getFocusOwner()
|
||||
{
|
||||
if(focusOwner == null)
|
||||
{
|
||||
for(Iterator iter=heavyweightDescendents.iterator(); iter.hasNext();)
|
||||
{
|
||||
Component child = (Component) iter.next();
|
||||
if(child.isFocusable())
|
||||
{
|
||||
focusOwner = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return focusOwner;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ import java.awt.Insets;
|
||||
import java.awt.MenuBar;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.FramePeer;
|
||||
|
||||
/**
|
||||
@@ -53,9 +54,9 @@ import java.awt.peer.FramePeer;
|
||||
* As a minimum, a subclass must implement all the remaining abstract methods
|
||||
* as well as the following methods:
|
||||
* <ul>
|
||||
* <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li>
|
||||
* <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li>
|
||||
* <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li>
|
||||
* <li>{@link ComponentPeer#getLocationOnScreen()}</li>
|
||||
* <li>{@link ComponentPeer#getGraphics()}</li>
|
||||
* <li>{@link ComponentPeer#createImage(int, int)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Roman Kennke (kennke@aicas.com)
|
||||
@@ -97,9 +98,9 @@ public abstract class SwingFramePeer
|
||||
*
|
||||
* @param g the graphics context to use for painting
|
||||
*/
|
||||
protected void peerPaint(Graphics g)
|
||||
protected void peerPaintComponent(Graphics g)
|
||||
{
|
||||
super.peerPaint(g);
|
||||
super.peerPaintComponent(g);
|
||||
if (menuBar != null)
|
||||
menuBar.peerPaint(g);
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Container;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.Label;
|
||||
import java.awt.Point;
|
||||
@@ -67,7 +69,14 @@ public class SwingLabelPeer
|
||||
extends JLabel
|
||||
implements SwingComponent
|
||||
{
|
||||
|
||||
Label label;
|
||||
|
||||
|
||||
SwingLabel(Label label)
|
||||
{
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this label.
|
||||
*
|
||||
@@ -131,8 +140,8 @@ public class SwingLabelPeer
|
||||
public boolean isShowing()
|
||||
{
|
||||
boolean retVal = false;
|
||||
if (SwingLabelPeer.this.awtComponent != null)
|
||||
retVal = SwingLabelPeer.this.awtComponent.isShowing();
|
||||
if (label != null)
|
||||
retVal = label.isShowing();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -149,7 +158,19 @@ public class SwingLabelPeer
|
||||
{
|
||||
return SwingLabelPeer.this.createImage(w, h);
|
||||
}
|
||||
|
||||
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
return SwingLabelPeer.this.getGraphics();
|
||||
}
|
||||
|
||||
public Container getParent()
|
||||
{
|
||||
Container par = null;
|
||||
if (label != null)
|
||||
par = label.getParent();
|
||||
return par;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,11 +181,11 @@ public class SwingLabelPeer
|
||||
public SwingLabelPeer(Label label)
|
||||
{
|
||||
super();
|
||||
SwingLabel swingLabel = new SwingLabel();
|
||||
SwingLabel swingLabel = new SwingLabel(label);
|
||||
swingLabel.setText(label.getText());
|
||||
swingLabel.setHorizontalAlignment(label.getAlignment());
|
||||
swingLabel.setOpaque(true);
|
||||
init(label, swingLabel);
|
||||
setAlignment(label.getAlignment());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +211,20 @@ public class SwingLabelPeer
|
||||
*/
|
||||
public void setAlignment(int alignment)
|
||||
{
|
||||
((JLabel) swingComponent.getJComponent()).setHorizontalAlignment(alignment);
|
||||
JLabel swingLabel = (JLabel) swingComponent.getJComponent();
|
||||
switch (alignment)
|
||||
{
|
||||
case Label.RIGHT:
|
||||
swingLabel.setHorizontalAlignment(JLabel.RIGHT);
|
||||
break;
|
||||
case Label.CENTER:
|
||||
swingLabel.setHorizontalAlignment(JLabel.CENTER);
|
||||
break;
|
||||
case Label.LEFT:
|
||||
default:
|
||||
swingLabel.setHorizontalAlignment(JLabel.LEFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
/* SwingListPeer.java -- A Swing based peer for AWT lists
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.List;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.peer.ListPeer;
|
||||
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
|
||||
public class SwingListPeer
|
||||
extends SwingComponentPeer
|
||||
implements ListPeer
|
||||
{
|
||||
|
||||
/**
|
||||
* A spezialized Swing scroller used to hold the list.
|
||||
*
|
||||
* @author Roman Kennke (kennke@aicas.com)
|
||||
*/
|
||||
private class SwingList
|
||||
extends JScrollPane
|
||||
implements SwingComponent
|
||||
{
|
||||
|
||||
SwingList(Component comp)
|
||||
{
|
||||
super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this label.
|
||||
*
|
||||
* @return <code>this</code>
|
||||
*/
|
||||
public JComponent getJComponent()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse events by forwarding it to
|
||||
* <code>processMouseEvent()</code>.
|
||||
*
|
||||
* @param ev the mouse event
|
||||
*/
|
||||
public void handleMouseEvent(MouseEvent ev)
|
||||
{
|
||||
ev.setSource(this);
|
||||
dispatchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force lightweight mouse dispatching.
|
||||
*/
|
||||
public boolean isLightweight()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse motion events by forwarding it to
|
||||
* <code>processMouseMotionEvent()</code>.
|
||||
*
|
||||
* @param ev the mouse motion event
|
||||
*/
|
||||
public void handleMouseMotionEvent(MouseEvent ev)
|
||||
{
|
||||
processMouseMotionEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles key events by forwarding it to <code>processKeyEvent()</code>.
|
||||
*
|
||||
* @param ev the mouse event
|
||||
*/
|
||||
public void handleKeyEvent(KeyEvent ev)
|
||||
{
|
||||
processKeyEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden so that this method returns the correct value even without a
|
||||
* peer.
|
||||
*
|
||||
* @return the screen location of the button
|
||||
*/
|
||||
public Point getLocationOnScreen()
|
||||
{
|
||||
return SwingListPeer.this.getLocationOnScreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden so that the isShowing method returns the correct value for the
|
||||
* swing button, even if it has no peer on its own.
|
||||
*
|
||||
* @return <code>true</code> if the button is currently showing,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean isShowing()
|
||||
{
|
||||
boolean retVal = false;
|
||||
if (SwingListPeer.this.awtComponent != null)
|
||||
retVal = SwingListPeer.this.awtComponent.isShowing();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden, so that the Swing button can create an Image without its
|
||||
* own peer.
|
||||
*
|
||||
* @param w the width of the image
|
||||
* @param h the height of the image
|
||||
*
|
||||
* @return an image
|
||||
*/
|
||||
public Image createImage(int w, int h)
|
||||
{
|
||||
return SwingListPeer.this.createImage(w, h);
|
||||
}
|
||||
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
return SwingListPeer.this.getGraphics();
|
||||
}
|
||||
|
||||
public Container getParent()
|
||||
{
|
||||
Container par = null;
|
||||
if (SwingListPeer.this.awtComponent != null)
|
||||
par = SwingListPeer.this.awtComponent.getParent();
|
||||
return par;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual Swing JList.
|
||||
*/
|
||||
private JList jList;
|
||||
|
||||
private DefaultListModel listModel;
|
||||
|
||||
public SwingListPeer(List list)
|
||||
{
|
||||
super();
|
||||
listModel = new DefaultListModel();
|
||||
jList = new JList(listModel);
|
||||
SwingList swingList = new SwingList(jList);
|
||||
init(list, swingList);
|
||||
|
||||
// Pull over the items from the list.
|
||||
String[] items = list.getItems();
|
||||
for (int i = 0 ; i < items.length; i++)
|
||||
addItem(items[i], i);
|
||||
}
|
||||
|
||||
public void add(String item, int index)
|
||||
{
|
||||
if (listModel != null)
|
||||
listModel.add(index, item);
|
||||
}
|
||||
|
||||
public void addItem(String item, int index)
|
||||
{
|
||||
if (listModel != null)
|
||||
listModel.add(index, item);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
if (listModel != null)
|
||||
listModel.clear();
|
||||
}
|
||||
|
||||
public void delItems(int startIndex, int endIndex)
|
||||
{
|
||||
if (listModel != null)
|
||||
listModel.removeRange(startIndex, endIndex);
|
||||
}
|
||||
|
||||
public void deselect(int index)
|
||||
{
|
||||
if (jList != null)
|
||||
{
|
||||
jList.getSelectionModel().removeSelectionInterval(index, index);
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize(int s)
|
||||
{
|
||||
Dimension d = null;
|
||||
if (jList != null)
|
||||
{
|
||||
d = jList.getComponent(s).getMinimumSize();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize(int s)
|
||||
{
|
||||
Dimension d = null;
|
||||
if (jList != null)
|
||||
{
|
||||
d = jList.getComponent(s).getPreferredSize();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public int[] getSelectedIndexes()
|
||||
{
|
||||
int[] sel = null;
|
||||
if (jList != null)
|
||||
{
|
||||
sel = jList.getSelectedIndices();
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
public void makeVisible(int index)
|
||||
{
|
||||
if (jList != null)
|
||||
{
|
||||
Component comp = jList.getComponent(index);
|
||||
jList.scrollRectToVisible(comp.getBounds());
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension minimumSize(int s)
|
||||
{
|
||||
Dimension d = null;
|
||||
if (jList != null)
|
||||
{
|
||||
d = jList.getComponent(s).getMinimumSize();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public Dimension preferredSize(int s)
|
||||
{
|
||||
Dimension d = null;
|
||||
if (jList != null)
|
||||
{
|
||||
d = jList.getComponent(s).getPreferredSize();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public void removeAll()
|
||||
{
|
||||
if (jList != null)
|
||||
{
|
||||
jList.removeAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void select(int index)
|
||||
{
|
||||
if (jList != null)
|
||||
{
|
||||
jList.setSelectedIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMultipleMode(boolean multi)
|
||||
{
|
||||
if (jList != null)
|
||||
{
|
||||
jList.setSelectionMode(multi
|
||||
? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
|
||||
: ListSelectionModel.SINGLE_SELECTION);
|
||||
}
|
||||
}
|
||||
|
||||
public void setMultipleSelections(boolean multi)
|
||||
{
|
||||
if (jList != null)
|
||||
{
|
||||
jList.setSelectionMode(multi
|
||||
? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
|
||||
: ListSelectionModel.SINGLE_SELECTION);
|
||||
}
|
||||
}
|
||||
|
||||
public void reshape(int x, int y, int width, int height)
|
||||
{
|
||||
if (swingComponent != null)
|
||||
{
|
||||
swingComponent.getJComponent().setBounds(x, y, width, height);
|
||||
swingComponent.getJComponent().validate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void peerPaint(Graphics g, boolean update)
|
||||
{
|
||||
super.peerPaint(g, update);
|
||||
jList.doLayout();
|
||||
jList.list();
|
||||
|
||||
Rectangle r = getBounds();
|
||||
g.setColor(Color.RED);
|
||||
g.drawRect(r.x, r.y, r.width, r.height);
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ public class SwingMenuBarPeer
|
||||
/**
|
||||
* Adds a help menu to the menu bar.
|
||||
*
|
||||
* @param menu the menu to add
|
||||
* @param m the menu to add
|
||||
*/
|
||||
public void addHelpMenu(Menu menu)
|
||||
{
|
||||
|
||||
@@ -39,7 +39,6 @@ exception statement from your version. */
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Panel;
|
||||
import java.awt.peer.LightweightPeer;
|
||||
import java.awt.peer.PanelPeer;
|
||||
|
||||
/**
|
||||
@@ -51,7 +50,7 @@ import java.awt.peer.PanelPeer;
|
||||
// necessary, but might be good for more consistend Look.
|
||||
public class SwingPanelPeer
|
||||
extends SwingContainerPeer
|
||||
implements PanelPeer, LightweightPeer
|
||||
implements PanelPeer
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -63,5 +62,6 @@ public class SwingPanelPeer
|
||||
public SwingPanelPeer(Panel panel)
|
||||
{
|
||||
super(panel);
|
||||
init(panel, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
/* SwingTextAreaPeer.java -- A Swing based peer for AWT textareas
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Classpath.
|
||||
|
||||
GNU Classpath is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU Classpath is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Classpath; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA.
|
||||
|
||||
Linking this library statically or dynamically with other modules is
|
||||
making a combined work based on this library. Thus, the terms and
|
||||
conditions of the GNU General Public License cover the whole
|
||||
combination.
|
||||
|
||||
As a special exception, the copyright holders of this library give you
|
||||
permission to link this library with independent modules to produce an
|
||||
executable, regardless of the license terms of these independent
|
||||
modules, and to copy and distribute the resulting executable under
|
||||
terms of your choice, provided that you also meet, for each linked
|
||||
independent module, the terms and conditions of the license of that
|
||||
module. An independent module is a module which is not derived from
|
||||
or based on this library. If you modify this library, you may extend
|
||||
this exception to your version of the library, but you are not
|
||||
obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.TextArea;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.im.InputMethodRequests;
|
||||
import java.awt.peer.TextAreaPeer;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
public class SwingTextAreaPeer
|
||||
extends SwingComponentPeer
|
||||
implements TextAreaPeer
|
||||
{
|
||||
|
||||
/**
|
||||
* A spezialized Swing scroller used to hold the textarea.
|
||||
*
|
||||
* @author Roman Kennke (kennke@aicas.com)
|
||||
*/
|
||||
private class SwingTextArea
|
||||
extends JScrollPane
|
||||
implements SwingComponent
|
||||
{
|
||||
|
||||
SwingTextArea(Component comp)
|
||||
{
|
||||
super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
|
||||
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this label.
|
||||
*
|
||||
* @return <code>this</code>
|
||||
*/
|
||||
public JComponent getJComponent()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse events by forwarding it to
|
||||
* <code>processMouseEvent()</code>.
|
||||
*
|
||||
* @param ev the mouse event
|
||||
*/
|
||||
public void handleMouseEvent(MouseEvent ev)
|
||||
{
|
||||
ev.setSource(this);
|
||||
dispatchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force lightweight mouse dispatching.
|
||||
*/
|
||||
public boolean isLightweight()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mouse motion events by forwarding it to
|
||||
* <code>processMouseMotionEvent()</code>.
|
||||
*
|
||||
* @param ev the mouse motion event
|
||||
*/
|
||||
public void handleMouseMotionEvent(MouseEvent ev)
|
||||
{
|
||||
processMouseMotionEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles key events by forwarding it to <code>processKeyEvent()</code>.
|
||||
*
|
||||
* @param ev the mouse event
|
||||
*/
|
||||
public void handleKeyEvent(KeyEvent ev)
|
||||
{
|
||||
processKeyEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden so that this method returns the correct value even without a
|
||||
* peer.
|
||||
*
|
||||
* @return the screen location of the button
|
||||
*/
|
||||
public Point getLocationOnScreen()
|
||||
{
|
||||
return SwingTextAreaPeer.this.getLocationOnScreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden so that the isShowing method returns the correct value for the
|
||||
* swing button, even if it has no peer on its own.
|
||||
*
|
||||
* @return <code>true</code> if the button is currently showing,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean isShowing()
|
||||
{
|
||||
boolean retVal = false;
|
||||
if (SwingTextAreaPeer.this.awtComponent != null)
|
||||
retVal = SwingTextAreaPeer.this.awtComponent.isShowing();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden, so that the Swing button can create an Image without its
|
||||
* own peer.
|
||||
*
|
||||
* @param w the width of the image
|
||||
* @param h the height of the image
|
||||
*
|
||||
* @return an image
|
||||
*/
|
||||
public Image createImage(int w, int h)
|
||||
{
|
||||
return SwingTextAreaPeer.this.createImage(w, h);
|
||||
}
|
||||
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
return SwingTextAreaPeer.this.getGraphics();
|
||||
}
|
||||
|
||||
public Container getParent()
|
||||
{
|
||||
Container par = null;
|
||||
if (SwingTextAreaPeer.this.awtComponent != null)
|
||||
par = SwingTextAreaPeer.this.awtComponent.getParent();
|
||||
return par;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual JTextArea.
|
||||
*/
|
||||
private JTextArea jTextArea;
|
||||
|
||||
public SwingTextAreaPeer(TextArea textArea)
|
||||
{
|
||||
super();
|
||||
System.err.println("new SwingTextAreaPeer");
|
||||
jTextArea = new JTextArea();
|
||||
SwingTextArea swingArea = new SwingTextArea(jTextArea);
|
||||
init(textArea, swingArea);
|
||||
|
||||
// Pull over the text from the text area.
|
||||
setText(textArea.getText());
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize(int rows, int cols)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize(int rows, int cols)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public void insert(String text, int pos)
|
||||
{
|
||||
jTextArea.insert(text, pos);
|
||||
}
|
||||
|
||||
public void insertText(String text, int pos)
|
||||
{
|
||||
jTextArea.insert(text, pos);
|
||||
}
|
||||
|
||||
public Dimension minimumSize(int rows, int cols)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public Dimension preferredSize(int rows, int cols)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public void replaceRange(String text, int start, int end)
|
||||
{
|
||||
jTextArea.replaceRange(text, start, end);
|
||||
}
|
||||
|
||||
public void replaceText(String text, int start, int end)
|
||||
{
|
||||
jTextArea.replaceRange(text, start, end);
|
||||
}
|
||||
|
||||
public long filterEvents(long filter)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getCaretPosition()
|
||||
{
|
||||
return jTextArea.getCaretPosition();
|
||||
}
|
||||
|
||||
public Rectangle getCharacterBounds(int pos)
|
||||
{
|
||||
Rectangle r;
|
||||
try
|
||||
{
|
||||
return jTextArea.modelToView(pos);
|
||||
}
|
||||
catch (BadLocationException ex)
|
||||
{
|
||||
r = null;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public int getIndexAtPoint(int x, int y)
|
||||
{
|
||||
return jTextArea.viewToModel(new Point(x, y));
|
||||
}
|
||||
|
||||
public InputMethodRequests getInputMethodRequests()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getSelectionEnd()
|
||||
{
|
||||
return jTextArea.getSelectionEnd();
|
||||
}
|
||||
|
||||
public int getSelectionStart()
|
||||
{
|
||||
return jTextArea.getSelectionStart();
|
||||
}
|
||||
|
||||
public String getText()
|
||||
{
|
||||
return jTextArea.getText();
|
||||
}
|
||||
|
||||
public void select(int start, int end)
|
||||
{
|
||||
jTextArea.select(start, end);
|
||||
}
|
||||
|
||||
public void setCaretPosition(int pos)
|
||||
{
|
||||
jTextArea.setCaretPosition(pos);
|
||||
}
|
||||
|
||||
public void setEditable(boolean editable)
|
||||
{
|
||||
jTextArea.setEditable(editable);
|
||||
}
|
||||
|
||||
public void setText(String text)
|
||||
{
|
||||
System.err.println("setText: " + text);
|
||||
jTextArea.setText(text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,10 @@ obligated to do so. If you do not wish to do so, delete this
|
||||
exception statement from your version. */
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
@@ -69,6 +72,13 @@ public class SwingTextFieldPeer
|
||||
implements SwingComponent
|
||||
{
|
||||
|
||||
TextField textField;
|
||||
|
||||
SwingTextField(TextField textField)
|
||||
{
|
||||
this.textField = textField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to provide normal behaviour even without a real peer
|
||||
* attached.
|
||||
@@ -90,8 +100,8 @@ public class SwingTextFieldPeer
|
||||
public boolean isShowing()
|
||||
{
|
||||
boolean retVal = false;
|
||||
if (SwingTextFieldPeer.this.awtComponent != null)
|
||||
retVal = SwingTextFieldPeer.this.awtComponent.isShowing();
|
||||
if (textField != null)
|
||||
retVal = textField.isShowing();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -151,7 +161,19 @@ public class SwingTextFieldPeer
|
||||
ev.setSource(this);
|
||||
processKeyEvent(ev);
|
||||
}
|
||||
|
||||
|
||||
public Container getParent()
|
||||
{
|
||||
Container par = null;
|
||||
if (textField != null)
|
||||
par = textField.getParent();
|
||||
return par;
|
||||
}
|
||||
|
||||
public Graphics getGraphics()
|
||||
{
|
||||
return SwingTextFieldPeer.this.getGraphics();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +184,7 @@ public class SwingTextFieldPeer
|
||||
*/
|
||||
public SwingTextFieldPeer(TextField textField)
|
||||
{
|
||||
SwingTextField swingTextField = new SwingTextField();
|
||||
SwingTextField swingTextField = new SwingTextField(textField);
|
||||
swingTextField.setText(textField.getText());
|
||||
init(textField, swingTextField);
|
||||
}
|
||||
@@ -283,7 +305,7 @@ public class SwingTextFieldPeer
|
||||
* @param startPos the start index of the selection
|
||||
* @param endPos the start index of the selection
|
||||
*/
|
||||
public void select(int startPos, int endPos)
|
||||
public void select(int start_pos, int endPos)
|
||||
{
|
||||
// TODO: Must be implemented.
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ exception statement from your version. */
|
||||
package gnu.java.awt.peer.swing;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.peer.ComponentPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
|
||||
/**
|
||||
@@ -48,9 +49,9 @@ import java.awt.peer.WindowPeer;
|
||||
* As a minimum, a subclass must implement all the remaining abstract methods
|
||||
* as well as the following methods:
|
||||
* <ul>
|
||||
* <li>{@link java.awt.peer.ComponentPeer#getLocationOnScreen()}</li>
|
||||
* <li>{@link java.awt.peer.ComponentPeer#getGraphics()}</li>
|
||||
* <li>{@link java.awt.peer.ComponentPeer#createImage(int, int)}</li>
|
||||
* <li>{@link ComponentPeer#getLocationOnScreen()}</li>
|
||||
* <li>{@link ComponentPeer#getGraphics()}</li>
|
||||
* <li>{@link ComponentPeer#createImage(int, int)}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Roman Kennke (kennke@aicas.com)
|
||||
@@ -68,5 +69,6 @@ public abstract class SwingWindowPeer
|
||||
public SwingWindowPeer(Window window)
|
||||
{
|
||||
super(window);
|
||||
init(window, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,13 +608,6 @@ public class XFontPeer
|
||||
throw new UnsupportedOperationException("Not yet implemented.");
|
||||
}
|
||||
|
||||
public Rectangle2D getStringBounds(Font font, CharacterIterator ci,
|
||||
int begin, int limit, FontRenderContext frc)
|
||||
{
|
||||
// TODO: Implement this.
|
||||
throw new UnsupportedOperationException("Not yet implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a font name + style + size specification into a X logical font
|
||||
* description (XLFD) as described here:
|
||||
|
||||
@@ -326,10 +326,4 @@ public class XFontPeer2
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public Rectangle2D getStringBounds(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext frc)
|
||||
{
|
||||
// FIXME: Implement this.
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user