diff options
Diffstat (limited to 'libjava/classpath/java/awt')
51 files changed, 3126 insertions, 1346 deletions
diff --git a/libjava/classpath/java/awt/AlphaComposite.java b/libjava/classpath/java/awt/AlphaComposite.java index 435cfd0..92b9e09 100644 --- a/libjava/classpath/java/awt/AlphaComposite.java +++ b/libjava/classpath/java/awt/AlphaComposite.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt; +import gnu.java.awt.java2d.AlphaCompositeContext; + import java.awt.image.ColorModel; import java.util.LinkedHashMap; import java.util.Map; @@ -137,14 +139,25 @@ public final class AlphaComposite implements Composite } return a; } + + /** + * Creates a {@link CompositeContext} that can be used to perform + * compositing operations according to this AlphaComposite settings. + * + * @param srcColorModel the color model of the source raster + * @param dstColorModel the color model of the destination raster + * @param hints the rendering hints to use + * + * @return a {@link CompositeContext} that can be used to perform + * compositing operations according to this AlphaComposite settings + */ public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) { - // XXX Implement. Sun uses undocumented implementation class - // sun.java2d.SunCompositeContext. - throw new Error("not implemented"); + return new AlphaCompositeContext(this, srcColorModel, dstColorModel); } + public float getAlpha() { return alpha; diff --git a/libjava/classpath/java/awt/BasicStroke.java b/libjava/classpath/java/awt/BasicStroke.java index 4eece75..bf111d0 100644 --- a/libjava/classpath/java/awt/BasicStroke.java +++ b/libjava/classpath/java/awt/BasicStroke.java @@ -38,6 +38,15 @@ exception statement from your version. */ package java.awt; +import gnu.java.awt.java2d.CubicSegment; +import gnu.java.awt.java2d.LineSegment; +import gnu.java.awt.java2d.QuadSegment; +import gnu.java.awt.java2d.Segment; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; import java.util.Arrays; /** @@ -109,6 +118,8 @@ public class BasicStroke implements Stroke /** The dash phase. */ private final float phase; + private Segment start, end; + /** * Creates a new <code>BasicStroke</code> instance with the given attributes. * @@ -249,8 +260,12 @@ public class BasicStroke implements Stroke */ public Shape createStrokedShape(Shape s) { - // FIXME: Implement this - throw new Error("not implemented"); + PathIterator pi = s.getPathIterator( new AffineTransform() ); + + if( dash == null ) + return solidStroke( pi ); + + return dashedStroke( pi ); } /** @@ -366,4 +381,355 @@ public class BasicStroke implements Stroke return width == s.width && cap == s.cap && join == s.join && limit == s.limit && Arrays.equals(dash, s.dash) && phase == s.phase; } + + private Shape solidStroke(PathIterator pi) + { + double[] coords = new double[6]; + double x, y, x0, y0; + boolean pathOpen = false; + GeneralPath output = new GeneralPath( ); + Segment[] p; + x = x0 = y = y0 = 0; + + while( !pi.isDone() ) + { + switch( pi.currentSegment(coords) ) + { + case PathIterator.SEG_MOVETO: + x0 = x = coords[0]; + y0 = y = coords[1]; + if( pathOpen ) + { + capEnds(); + convertPath(output, start); + start = end = null; + pathOpen = false; + } + break; + + case PathIterator.SEG_LINETO: + p = (new LineSegment(x, y, coords[0], coords[1])). + getDisplacedSegments(width/2.0); + if( !pathOpen ) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[0]; + y = coords[1]; + break; + + case PathIterator.SEG_QUADTO: + p = (new QuadSegment(x, y, coords[0], coords[1], coords[2], + coords[3])).getDisplacedSegments(width/2.0); + if( !pathOpen ) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[0]; + y = coords[1]; + break; + + case PathIterator.SEG_CUBICTO: + p = new CubicSegment(x, y, coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]).getDisplacedSegments(width/2.0); + if( !pathOpen ) + { + start = p[0]; + end = p[1]; + pathOpen = true; + } + else + addSegments(p); + + x = coords[0]; + y = coords[1]; + break; + + case PathIterator.SEG_CLOSE: + p = (new LineSegment(x, y, x0, y0)).getDisplacedSegments(width/2.0); + addSegments(p); + convertPath(output, start); + convertPath(output, end); + start = end = null; + pathOpen = false; + break; + } + pi.next(); + } + + if( pathOpen ) + { + capEnds(); + convertPath(output, start); + } + return output; + } + + private Shape dashedStroke(PathIterator pi) + { + GeneralPath out = new GeneralPath(); + return out; + } + + /** + * Cap the ends of the path (joining the start and end list of segments) + */ + private void capEnds() + { + Segment returnPath = end.last; + + end.reverseAll(); // reverse the path. + end = null; + capEnd(start, returnPath); + start.last = returnPath.last; + end = null; + + capEnd(start, start); + } + + /** + * Convert and add the linked list of Segments in s to a GeneralPath p. + */ + private void convertPath(GeneralPath p, Segment s) + { + Segment v = s; + p.moveTo((float)s.P1.getX(), (float)s.P1.getY()); + + do + { + if(v instanceof LineSegment) + p.lineTo((float)v.P2.getX(), (float)v.P2.getY()); + else if(v instanceof QuadSegment) + p.quadTo((float)((QuadSegment)v).cp.getX(), + (float)((QuadSegment)v).cp.getY(), + (float)v.P2.getX(), + (float)v.P2.getY()); + else if(v instanceof CubicSegment) + p.curveTo((float)((CubicSegment)v).cp1.getX(), + (float)((CubicSegment)v).cp1.getY(), + (float)((CubicSegment)v).cp2.getX(), + (float)((CubicSegment)v).cp2.getY(), + (float)v.P2.getX(), + (float)v.P2.getY()); + v = v.next; + } while(v != s && v != null); + + p.closePath(); + } + + /** + * Add to segments to start and end, joining the outer pair and + */ + private void addSegments(Segment[] segments) + { + double[] p0 = start.last.last(); + double[] p1 = new double[]{start.last.P2.getX(), start.last.P2.getY()}; + double[] p2 = new double[]{segments[0].P1.getX(), segments[0].P1.getY()}; + double[] p3 = segments[0].first(); + Point2D p; + + double det = (p1[0] - p0[0])*(p3[1] - p2[1]) - + (p3[0] - p2[0])*(p1[1] - p0[1]); + + if( det > 0 ) + { + // start and segment[0] form the 'inner' part of a join, + // connect the overlapping segments + p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], false); + if( p == null ) + { + // Dodgy. + start.add(new LineSegment(start.last.P2, segments[0].P1)); + p = new Point2D.Double((segments[0].P1.getX()+ start.last.P2.getX())/2.0, + (segments[0].P1.getY()+ start.last.P2.getY())/2.0); + } + else + segments[0].P1 = start.last.P2 = p; + + start.add( segments[0] ); + joinSegments(end, segments[1], p); + } + else + { + // end and segment[1] form the 'inner' part + p0 = end.last.last(); + p1 = new double[]{end.last.P2.getX(), end.last.P2.getY()}; + p2 = new double[]{segments[1].P1.getX(), segments[1].P1.getY()}; + p3 = segments[1].first(); + + p = lineIntersection(p0[0],p0[1],p1[0],p1[1], + p2[0],p2[1],p3[0],p3[1], false); + if( p == null ) + { + // Dodgy. + end.add(new LineSegment(end.last.P2, segments[1].P1)); + p = new Point2D.Double((segments[1].P1.getX()+ end.last.P2.getX())/2.0, + (segments[1].P1.getY()+ end.last.P2.getY())/2.0); + } + else + segments[1].P1 = end.last.P2 = p; + + end.add( segments[1] ); + joinSegments(start, segments[0], p); + } + } + + /** + * Make a cap between a and b segments, + * where a-->b is the direction of iteration. + */ + private void capEnd(Segment a, Segment b) + { + double[] p0, p1; + double dx, dy, l; + Point2D c1,c2; + + switch( cap ) + { + case CAP_BUTT: + a.add(new LineSegment(a.last.P2, b.P1)); + break; + + case CAP_SQUARE: + p0 = a.last.last(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + dx = p1[0] - p0[0]; + dy = p1[1] - p0[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = 0.5*width*dx/l; + dy = 0.5*width*dy/l; + c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); + c2 = new Point2D.Double(b.P1.getX() + dx, b.P1.getY() + dy); + a.add(new LineSegment(a.last.P2, c1)); + a.add(new LineSegment(c1, c2)); + a.add(new LineSegment(c2, b.P1)); + break; + + case CAP_ROUND: + p0 = a.last.last(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + dx = p1[0] - p0[0]; + dy = p1[1] - p0[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = (2.0/3.0)*width*dx/l; + dy = (2.0/3.0)*width*dy/l; + c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); + c2 = new Point2D.Double(b.P1.getX() + dx, b.P1.getY() + dy); + a.add(new CubicSegment(a.last.P2, c1, c2, b.P1)); + break; + } + a.add(b); + } + + /** + * Returns the intersection of two lines, or null if there isn't one. + * @param infinite - true if the lines should be regarded as infinite, false + * if the intersection must be within the given segments. + * @return a Point2D or null. + */ + private Point2D lineIntersection(double X1, double Y1, + double X2, double Y2, + double X3, double Y3, + double X4, double Y4, + boolean infinite) + { + double x1 = X1; + double y1 = Y1; + double rx = X2 - x1; + double ry = Y2 - y1; + + double x2 = X3; + double y2 = Y3; + double sx = X4 - x2; + double sy = Y4 - y2; + + double determinant = sx * ry - sy * rx; + double nom = (sx * (y2 - y1) + sy * (x1 - x2)); + + // lines can be considered parallel. + if (Math.abs(determinant) < 1E-6) + return null; + + nom = nom / determinant; + + // check if lines are within the bounds + if(!infinite && (nom > 1.0 || nom < 0.0)) + return null; + + return new Point2D.Double(x1 + nom * rx, y1 + nom * ry); + } + + /** + * Join a and b segments, where a-->b is the direction of iteration. + * + * insideP is the inside intersection point of the join, needed for + * calculating miter lengths. + */ + private void joinSegments(Segment a, Segment b, Point2D insideP) + { + double[] p0, p1; + double dx, dy, l; + Point2D c1,c2; + + switch( join ) + { + case JOIN_MITER: + p0 = a.last.last(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + double[] p2 = new double[]{b.P1.getX(), b.P1.getY()}; + double[] p3 = b.first(); + Point2D p = lineIntersection(p0[0],p0[1],p1[0],p1[1],p2[0],p2[1],p3[0],p3[1], true); + if( p == null || insideP == null ) + a.add(new LineSegment(a.last.P2, b.P1)); + else if((p.distance(insideP)/width) < limit) + { + a.add(new LineSegment(a.last.P2, p)); + a.add(new LineSegment(p, b.P1)); + } + else + { + // outside miter limit, do a bevel join. + a.add(new LineSegment(a.last.P2, b.P1)); + } + break; + + case JOIN_ROUND: + p0 = a.last.last(); + p1 = new double[]{a.last.P2.getX(), a.last.P2.getY()}; + dx = p1[0] - p0[0]; + dy = p1[1] - p0[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = 0.5*width*dx/l; + dy = 0.5*width*dy/l; + c1 = new Point2D.Double(p1[0] + dx, p1[1] + dy); + + p0 = new double[]{b.P1.getX(), b.P1.getY()}; + p1 = b.first(); + + dx = p0[0] - p1[0]; // backwards direction. + dy = p0[1] - p1[1]; + l = Math.sqrt(dx * dx + dy * dy); + dx = 0.5*width*dx/l; + dy = 0.5*width*dy/l; + c2 = new Point2D.Double(p0[0] + dx, p0[1] + dy); + a.add(new CubicSegment(a.last.P2, c1, c2, b.P1)); + break; + + case JOIN_BEVEL: + a.add(new LineSegment(a.last.P2, b.P1)); + break; + } + a.add(b); + } } diff --git a/libjava/classpath/java/awt/Button.java b/libjava/classpath/java/awt/Button.java index e788d82..ae897a2 100644 --- a/libjava/classpath/java/awt/Button.java +++ b/libjava/classpath/java/awt/Button.java @@ -98,7 +98,7 @@ private transient ActionListener action_listeners; protected class AccessibleAWTButton extends AccessibleAWTComponent implements AccessibleAction, AccessibleValue { - public static final long serialVersionUID = -5932203980244017102L; + private static final long serialVersionUID = -5932203980244017102L; protected AccessibleAWTButton() { diff --git a/libjava/classpath/java/awt/Choice.java b/libjava/classpath/java/awt/Choice.java index 2e55d19..90a8d31 100644 --- a/libjava/classpath/java/awt/Choice.java +++ b/libjava/classpath/java/awt/Choice.java @@ -556,6 +556,17 @@ processEvent(AWTEvent event) super.processEvent(event); } +void +dispatchEventImpl(AWTEvent e) +{ + if (e.id <= ItemEvent.ITEM_LAST + && e.id >= ItemEvent.ITEM_FIRST + && (item_listeners != null || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0)) + processEvent(e); + else + super.dispatchEventImpl(e); +} + /*************************************************************************/ /** diff --git a/libjava/classpath/java/awt/Component.java b/libjava/classpath/java/awt/Component.java index de01fc1..dbbec8a 100644 --- a/libjava/classpath/java/awt/Component.java +++ b/libjava/classpath/java/awt/Component.java @@ -906,7 +906,7 @@ public abstract class Component // The JDK repaints the component before invalidating the parent. // So do we. - if (isShowing()) + if (isShowing() && isLightweight()) repaint(); // Invalidate the parent if we have one. The component itself must // not be invalidated. We also avoid NullPointerException with @@ -1075,8 +1075,6 @@ public abstract class Component Component p = parent; if (p != null) return p.getFont(); - if (peer != null) - return peer.getGraphics().getFont(); return null; } @@ -2315,6 +2313,10 @@ public abstract class Component if (oldEvent != null) postEvent (oldEvent); + // Give toolkit a chance to dispatch the event + // to globally registered listeners. + Toolkit.getDefaultToolkit().globalDispatchEvent(e); + // Some subclasses in the AWT package need to override this behavior, // hence the use of dispatchEventImpl(). dispatchEventImpl(e); @@ -3089,6 +3091,8 @@ public abstract class Component mouseListener.mouseClicked(e); break; case MouseEvent.MOUSE_ENTERED: + if( isLightweight() ) + setCursor( getCursor() ); mouseListener.mouseEntered(e); break; case MouseEvent.MOUSE_EXITED: @@ -3101,7 +3105,6 @@ public abstract class Component mouseListener.mouseReleased(e); break; } - e.consume(); } /** @@ -4079,14 +4082,9 @@ public abstract class Component */ public Container getFocusCycleRootAncestor () { - if (this instanceof Window - && ((Container) this).isFocusCycleRoot ()) - return (Container) this; - Container parent = getParent (); - while (parent != null - && !parent.isFocusCycleRoot ()) + while (parent != null && !parent.isFocusCycleRoot()) parent = parent.getParent (); return parent; @@ -4114,9 +4112,32 @@ public abstract class Component */ public void nextFocus () { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentAfter(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); - manager.focusNextComponent (this); + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } } /** @@ -4128,9 +4149,32 @@ public abstract class Component */ public void transferFocusBackward () { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + // Find the nearest valid (== showing && focusable && enabled) focus + // cycle root ancestor and the focused component in it. + Container focusRoot = getFocusCycleRootAncestor(); + Component focusComp = this; + while (focusRoot != null + && ! (focusRoot.isShowing() && focusRoot.isFocusable() + && focusRoot.isEnabled())) + { + focusComp = focusRoot; + focusRoot = focusComp.getFocusCycleRootAncestor(); + } + + if (focusRoot != null) + { + // First try to get the componentBefore from the policy. + FocusTraversalPolicy policy = focusRoot.getFocusTraversalPolicy(); + Component nextFocus = policy.getComponentBefore(focusRoot, focusComp); + + // If this fails, then ask for the defaultComponent. + if (nextFocus == null) + nextFocus = policy.getDefaultComponent(focusRoot); - manager.focusPreviousComponent (this); + // Request focus on this component, if not null. + if (nextFocus != null) + nextFocus.requestFocus(); + } } /** @@ -4144,9 +4188,63 @@ public abstract class Component */ public void transferFocusUpCycle () { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + // Find the nearest focus cycle root ancestor that is itself + // focusable, showing and enabled. + Container focusCycleRoot = getFocusCycleRootAncestor(); + while (focusCycleRoot != null && + ! (focusCycleRoot.isShowing() && focusCycleRoot.isFocusable() + && focusCycleRoot.isEnabled())) + { + focusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor(); + } + + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + + if (focusCycleRoot != null) + { + // If we found a focus cycle root, then we make this the new + // focused component, and make it's focus cycle root the new + // global focus cycle root. If the found root has no focus cycle + // root ancestor itself, then the component will be both the focused + // component and the new global focus cycle root. + Container focusCycleAncestor = + focusCycleRoot.getFocusCycleRootAncestor(); + Container globalFocusCycleRoot; + if (focusCycleAncestor == null) + globalFocusCycleRoot = focusCycleRoot; + else + globalFocusCycleRoot = focusCycleAncestor; + + fm.setGlobalCurrentFocusCycleRoot(globalFocusCycleRoot); + focusCycleRoot.requestFocus(); + } + else + { + // If this component has no applicable focus cycle root, we try + // find the nearest window and set this as the new global focus cycle + // root and the default focus component of this window the new focused + // component. + Container cont; + if (this instanceof Container) + cont = (Container) this; + else + cont = getParent(); - manager.upFocusCycle (this); + while (cont != null && !(cont instanceof Window)) + cont = cont.getParent(); + + if (cont != null) + { + FocusTraversalPolicy policy = cont.getFocusTraversalPolicy(); + Component focusComp = policy.getDefaultComponent(cont); + if (focusComp != null) + { + fm.setGlobalCurrentFocusCycleRoot(cont); + focusComp.requestFocus(); + } + } + } } /** @@ -4876,7 +4974,7 @@ p * <li>the set of backward traversal keys oldKey = Event.UP; break; default: - oldKey = newKey; + oldKey = (int) ((KeyEvent) e).getKeyChar(); } translated = new Event (target, when, oldID, @@ -4922,10 +5020,6 @@ p * <li>the set of backward traversal keys void dispatchEventImpl(AWTEvent e) { - // Give toolkit a chance to dispatch the event - // to globally registered listeners. - Toolkit.getDefaultToolkit().globalDispatchEvent(e); - // This boolean tells us not to process focus events when the focus // opposite component is the same as the focus component. boolean ignoreFocus = @@ -4934,6 +5028,10 @@ p * <li>the set of backward traversal keys if (eventTypeEnabled (e.id)) { + if (e.id != PaintEvent.PAINT && e.id != PaintEvent.UPDATE + && !ignoreFocus) + processEvent(e); + // the trick we use to communicate between dispatch and redispatch // is to have KeyboardFocusManager.redispatch synchronize on the // object itself. we then do not redispatch to KeyboardFocusManager @@ -4954,14 +5052,11 @@ p * <li>the set of backward traversal keys .dispatchEvent(e)) return; case MouseEvent.MOUSE_PRESSED: - if (isLightweight()) - requestFocus(); + if (isLightweight() && !e.isConsumed()) + requestFocus(); break; } } - if (e.id != PaintEvent.PAINT && e.id != PaintEvent.UPDATE - && !ignoreFocus) - processEvent(e); } if (peer != null) @@ -4978,6 +5073,15 @@ p * <li>the set of backward traversal keys switch (type) { + case HierarchyEvent.HIERARCHY_CHANGED: + return (hierarchyListener != null + || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0); + + case HierarchyEvent.ANCESTOR_MOVED: + case HierarchyEvent.ANCESTOR_RESIZED: + return (hierarchyBoundsListener != null + || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0); + case ComponentEvent.COMPONENT_HIDDEN: case ComponentEvent.COMPONENT_MOVED: case ComponentEvent.COMPONENT_RESIZED: @@ -5002,6 +5106,9 @@ p * <li>the set of backward traversal keys case MouseEvent.MOUSE_DRAGGED: return (mouseMotionListener != null || (eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0); + case MouseEvent.MOUSE_WHEEL: + return (mouseWheelListener != null + || (eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0); case FocusEvent.FOCUS_GAINED: case FocusEvent.FOCUS_LOST: @@ -5289,7 +5396,7 @@ p * <li>the set of backward traversal keys */ public String getAccessibleName() { - return accessibleName == null ? getName() : accessibleName; + return accessibleName; } /** @@ -5329,8 +5436,10 @@ p * <li>the set of backward traversal keys s.add(AccessibleState.FOCUSABLE); if (isFocusOwner()) s.add(AccessibleState.FOCUSED); - if (isOpaque()) - s.add(AccessibleState.OPAQUE); + // Note: While the java.awt.Component has an 'opaque' property, it + // seems that it is not added to the accessible state set here, even + // if this property is true. However, it is handled for + // javax.swing.JComponent, so we add it there. if (Component.this.isShowing()) s.add(AccessibleState.SHOWING); if (Component.this.isVisible()) @@ -5614,7 +5723,7 @@ p * <li>the set of backward traversal keys */ public Point getLocation() { - return Component.this.isShowing() ? Component.this.getLocation() : null; + return Component.this.getLocation(); } /** @@ -5638,7 +5747,7 @@ p * <li>the set of backward traversal keys */ public Rectangle getBounds() { - return Component.this.isShowing() ? Component.this.getBounds() : null; + return Component.this.getBounds(); } /** @@ -5661,7 +5770,7 @@ p * <li>the set of backward traversal keys */ public Dimension getSize() { - return Component.this.isShowing() ? Component.this.getSize() : null; + return Component.this.getSize(); } /** diff --git a/libjava/classpath/java/awt/Container.java b/libjava/classpath/java/awt/Container.java index 41892ca..2419a7b 100644 --- a/libjava/classpath/java/awt/Container.java +++ b/libjava/classpath/java/awt/Container.java @@ -388,10 +388,6 @@ public class Container extends Component ContainerListener[] listeners = getContainerListeners(); for (int i = 0; i < listeners.length; i++) listeners[i].componentAdded(ce); - - // Repaint this container. - repaint(comp.getX(), comp.getY(), comp.getWidth(), - comp.getHeight()); } } @@ -968,6 +964,13 @@ public class Container extends Component * child component claims the point, the container itself is returned, * unless the point does not exist within this container, in which * case <code>null</code> is returned. + * + * When components overlap, the first component is returned. The component + * that is closest to (x, y), containing that location, is returned. + * Heavyweight components take precedence of lightweight components. + * + * This function does not ignore invisible components. If there is an invisible + * component at (x,y), it will be returned. * * @param x The X coordinate of the point. * @param y The Y coordinate of the point. @@ -987,7 +990,14 @@ public class Container extends Component * child component claims the point, the container itself is returned, * unless the point does not exist within this container, in which * case <code>null</code> is returned. - * + * + * When components overlap, the first component is returned. The component + * that is closest to (x, y), containing that location, is returned. + * Heavyweight components take precedence of lightweight components. + * + * This function does not ignore invisible components. If there is an invisible + * component at (x,y), it will be returned. + * * @param x The x position of the point to return the component at. * @param y The y position of the point to return the component at. * @@ -1002,17 +1012,28 @@ public class Container extends Component { if (!contains (x, y)) return null; + + // First find the component closest to (x,y) that is a heavyweight. for (int i = 0; i < ncomponents; ++i) { - // Ignore invisible children... - if (!component[i].isVisible ()) - continue; - - int x2 = x - component[i].x; - int y2 = y - component[i].y; - if (component[i].contains (x2, y2)) - return component[i]; + Component comp = component[i]; + int x2 = x - comp.x; + int y2 = y - comp.y; + if (comp.contains (x2, y2) && !comp.isLightweight()) + return comp; } + + // if a heavyweight component is not found, look for a lightweight + // closest to (x,y). + for (int i = 0; i < ncomponents; ++i) + { + Component comp = component[i]; + int x2 = x - comp.x; + int y2 = y - comp.y; + if (comp.contains (x2, y2) && comp.isLightweight()) + return comp; + } + return this; } } @@ -1025,6 +1046,13 @@ public class Container extends Component * unless the point does not exist within this container, in which * case <code>null</code> is returned. * + * The top-most child component is returned in the case where components overlap. + * This is determined by finding the component closest to (x,y) and contains + * that location. Heavyweight components take precedence of lightweight components. + * + * This function does not ignore invisible components. If there is an invisible + * component at (x,y), it will be returned. + * * @param p The point to return the component at. * @return The component containing the specified point, or <code>null</code> * if there is no such point. @@ -1034,6 +1062,22 @@ public class Container extends Component return getComponentAt (p.x, p.y); } + /** + * Locates the visible child component that contains the specified position. + * The top-most child component is returned in the case where there is overlap + * in the components. If the containing child component is a Container, + * this method will continue searching for the deepest nested child + * component. Components which are not visible are ignored during the search. + * + * findComponentAt differs from getComponentAt, because it recursively + * searches a Container's children. + * + * @param x - x coordinate + * @param y - y coordinate + * @return null if the component does not contain the position. + * If there is no child component at the requested point and the point is + * within the bounds of the container the container itself is returned. + */ public Component findComponentAt(int x, int y) { synchronized (getTreeLock ()) @@ -1067,53 +1111,20 @@ public class Container extends Component } /** - * Finds the visible child component that contains the specified position. - * The top-most child is returned in the case where there is overlap. - * If the top-most child is transparent and has no MouseListeners attached, - * we discard it and return the next top-most component containing the - * specified position. - * @param x the x coordinate - * @param y the y coordinate - * @return null if the <code>this</code> does not contain the position, - * otherwise the top-most component (out of this container itself and - * its descendants) meeting the criteria above. + * Locates the visible child component that contains the specified position. + * The top-most child component is returned in the case where there is overlap + * in the components. If the containing child component is a Container, + * this method will continue searching for the deepest nested child + * component. Components which are not visible are ignored during the search. + * + * findComponentAt differs from getComponentAt, because it recursively + * searches a Container's children. + * + * @param p - the component's location + * @return null if the component does not contain the position. + * If there is no child component at the requested point and the point is + * within the bounds of the container the container itself is returned. */ - Component findComponentForMouseEventAt(int x, int y) - { - synchronized (getTreeLock()) - { - if (!contains(x, y)) - return null; - - for (int i = 0; i < ncomponents; ++i) - { - // Ignore invisible children... - if (!component[i].isVisible()) - continue; - - int x2 = x - component[i].x; - int y2 = y - component[i].y; - // We don't do the contains() check right away because - // findComponentAt would redundantly do it first thing. - if (component[i] instanceof Container) - { - Container k = (Container) component[i]; - Component r = k.findComponentForMouseEventAt(x2, y2); - if (r != null) - return r; - } - else if (component[i].contains(x2, y2)) - return component[i]; - } - - //don't return transparent components with no MouseListeners - if (getMouseListeners().length == 0 - && getMouseMotionListeners().length == 0) - return null; - return this; - } - } - public Component findComponentAt(Point p) { return findComponentAt(p.x, p.y); @@ -1454,7 +1465,7 @@ public class Container extends Component { Container ancestor = getFocusCycleRootAncestor (); - if (ancestor != this) + if (ancestor != this && ancestor != null) return ancestor.getFocusTraversalPolicy (); else { @@ -1524,9 +1535,16 @@ public class Container extends Component */ public void transferFocusDownCycle () { - KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); - - manager.downFocusCycle (this); + if (isFocusCycleRoot()) + { + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + fm.setGlobalCurrentFocusCycleRoot(this); + FocusTraversalPolicy policy = getFocusTraversalPolicy(); + Component defaultComponent = policy.getDefaultComponent(this); + if (defaultComponent != null) + defaultComponent.requestFocus(); + } } /** diff --git a/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java b/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java index 46b56d3..a5cb7da 100644 --- a/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java +++ b/libjava/classpath/java/awt/DefaultFocusTraversalPolicy.java @@ -61,6 +61,8 @@ package java.awt; public class DefaultFocusTraversalPolicy extends ContainerOrderFocusTraversalPolicy { + private static final long serialVersionUID = 8876966522510157497L; + /** * Construct a default focus traversal policy. */ diff --git a/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java index bce6352..a60cefd 100644 --- a/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java +++ b/libjava/classpath/java/awt/DefaultKeyboardFocusManager.java @@ -478,59 +478,25 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager public void focusPreviousComponent (Component comp) { - Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; - Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); - FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); - - Component previous = policy.getComponentBefore (focusCycleRoot, focusComp); - if (previous != null) - previous.requestFocusInWindow (); + if (comp != null) + comp.transferFocusBackward(); } public void focusNextComponent (Component comp) { - Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; - Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); - FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); - - Component next = policy.getComponentAfter (focusCycleRoot, focusComp); - if (next != null) - next.requestFocusInWindow (); + if (comp != null) + comp.transferFocus(); } public void upFocusCycle (Component comp) { - Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; - Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); - - if (focusCycleRoot instanceof Window) - { - FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); - Component defaultComponent = policy.getDefaultComponent (focusCycleRoot); - if (defaultComponent != null) - defaultComponent.requestFocusInWindow (); - } - else - { - Container parentFocusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor (); - - focusCycleRoot.requestFocusInWindow (); - setGlobalCurrentFocusCycleRoot (parentFocusCycleRoot); - } + if (comp != null) + comp.transferFocusUpCycle(); } public void downFocusCycle (Container cont) { - if (cont == null) - return; - - if (cont.isFocusCycleRoot (cont)) - { - FocusTraversalPolicy policy = cont.getFocusTraversalPolicy (); - Component defaultComponent = policy.getDefaultComponent (cont); - if (defaultComponent != null) - defaultComponent.requestFocusInWindow (); - setGlobalCurrentFocusCycleRoot (cont); - } + if (cont != null) + cont.transferFocusDownCycle(); } } // class DefaultKeyboardFocusManager diff --git a/libjava/classpath/java/awt/Dialog.java b/libjava/classpath/java/awt/Dialog.java index 7e5e721..55c3371 100644 --- a/libjava/classpath/java/awt/Dialog.java +++ b/libjava/classpath/java/awt/Dialog.java @@ -1,39 +1,40 @@ /* Dialog.java -- An AWT dialog box - Copyright (C) 1999, 2000, 2001, 2002, 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. */ + Copyright (C) 1999, 2000, 2001, 2002, 2005, 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 java.awt; @@ -46,457 +47,422 @@ import javax.accessibility.AccessibleState; import javax.accessibility.AccessibleStateSet; /** - * A dialog box widget class. - * + * <code>Dialog</code> provides a top-level window normally used to receive + * user input in applications. + * <p> + * A dialog always has another top-level window as owner and is only visible + * if this owner is visible to the user. The default layout of dialogs is the + * <code>BorderLayout</code>. Dialogs can be modal (blocks user input to other + * components) or non-modal (user input in other components are allowed). + * </p> + * * @author Aaron M. Renn (arenn@urbanophile.com) * @author Tom Tromey (tromey@redhat.com) */ public class Dialog extends Window { + // Serialization constant + private static final long serialVersionUID = 5920926903803293709L; -/* - * Static Variables - */ - -// Serialization constant -private static final long serialVersionUID = 5920926903803293709L; - -/*************************************************************************/ - -/* - * Instance Variables - */ - -/** - * @serial Indicates whether or not this dialog box is modal. - */ -private boolean modal; - -/** - * @serial Indicates whether or not this dialog box is resizable. - */ -private boolean resizable = true; - -/** - * @serial The title string for this dialog box, which can be - * <code>null</code>. - */ -private String title; - -/** - * This field indicates whether the dialog is undecorated or not. - */ -private boolean undecorated = false; - -/** - * Indicates that we are blocked for modality in show - */ -private boolean blocked = false; - -/** - * Secondary EventQueue to handle AWT events while - * we are blocked for modality in show - */ -private EventQueue eq2 = null; - -/*************************************************************************/ - -/* - * Constructors - */ - -/** - * Initializes a new instance of <code>Dialog</code> with the specified - * parent, that is resizable and not modal, and which has no title. - * - * @param parent The parent frame of this dialog box. - * - * @exception IllegalArgumentException If the owner's GraphicsConfiguration - * is not from a screen device, or if owner is null. This exception is always - * thrown when GraphicsEnvironment.isHeadless() returns true. - */ -public -Dialog(Frame parent) -{ - this(parent, "", false); -} - -/*************************************************************************/ - -/** - * Initializes a new instance of <code>Dialog</code> with the specified - * parent and modality, that is resizable and which has no title. - * - * @param parent The parent frame of this dialog box. - * @param modal <code>true</code> if this dialog box is modal, - * <code>false</code> otherwise. - * - * @exception IllegalArgumentException If the owner's GraphicsConfiguration - * is not from a screen device, or if owner is null. This exception is always - * thrown when GraphicsEnvironment.isHeadless() returns true. - */ -public -Dialog(Frame parent, boolean modal) -{ - this(parent, "", modal); -} - -/*************************************************************************/ - -/** - * Initializes a new instance of <code>Dialog</code> with the specified - * parent, that is resizable and not modal, and which has the specified - * title. - * - * @param parent The parent frame of this dialog box. - * @param title The title string for this dialog box. - * - * @exception IllegalArgumentException If the owner's GraphicsConfiguration - * is not from a screen device, or if owner is null. This exception is always - * thrown when GraphicsEnvironment.isHeadless() returns true. - */ -public -Dialog(Frame parent, String title) -{ - this(parent, title, false); -} - -/*************************************************************************/ - -/** - * Initializes a new instance of <code>Dialog</code> with the specified, - * parent, title, and modality, that is resizable. - * - * @param parent The parent frame of this dialog box. - * @param title The title string for this dialog box. - * @param modal <code>true</code> if this dialog box is modal, - * <code>false</code> otherwise. - * - * @exception IllegalArgumentException If owner is null or - * GraphicsEnvironment.isHeadless() returns true. - */ -public -Dialog(Frame parent, String title, boolean modal) -{ - this (parent, title, modal, parent.getGraphicsConfiguration ()); -} - -/** - * Initializes a new instance of <code>Dialog</code> with the specified, - * parent, title, modality and <code>GraphicsConfiguration</code>, - * that is resizable. - * - * @param parent The parent frame of this dialog box. - * @param title The title string for this dialog box. - * @param modal <code>true</code> if this dialog box is modal, - * <code>false</code> otherwise. - * @param gc The <code>GraphicsConfiguration</code> object to use. - * - * @exception IllegalArgumentException If owner is null, the - * GraphicsConfiguration is not a screen device or - * GraphicsEnvironment.isHeadless() returns true. - * - * @since 1.4 - */ -public -Dialog (Frame parent, String title, boolean modal, GraphicsConfiguration gc) -{ - super (parent, gc); - - // A null title is equivalent to an empty title - this.title = (title != null) ? title : ""; - this.modal = modal; - visible = false; - - setLayout(new BorderLayout()); -} - -/** - * Initializes a new instance of <code>Dialog</code> with the specified, - * parent, that is resizable. - * - * @exception IllegalArgumentException If parent is null. This exception is - * always thrown when GraphicsEnvironment.isHeadless() returns true. - * - * @since 1.2 - */ -public -Dialog (Dialog owner) -{ - this (owner, "", false, owner.getGraphicsConfiguration ()); -} - -/** - * Initializes a new instance of <code>Dialog</code> with the specified, - * parent and title, that is resizable. - * - * @exception IllegalArgumentException If parent is null. This exception is - * always thrown when GraphicsEnvironment.isHeadless() returns true. - * - * @since 1.2 - */ -public -Dialog (Dialog owner, String title) -{ - this (owner, title, false, owner.getGraphicsConfiguration ()); -} - -/** - * Initializes a new instance of <code>Dialog</code> with the specified, - * parent, title and modality, that is resizable. - * - * @exception IllegalArgumentException If parent is null. This exception is - * always thrown when GraphicsEnvironment.isHeadless() returns true. - * - * @since 1.2 - */ -public -Dialog (Dialog owner, String title, boolean modal) -{ - this (owner, title, modal, owner.getGraphicsConfiguration ()); -} + /** + * @serial Indicates whether or not this dialog box is modal. + */ + private boolean modal; -/** - * Initializes a new instance of <code>Dialog</code> with the specified, - * parent, title, modality and <code>GraphicsConfiguration</code>, - * that is resizable. - * - * @exception IllegalArgumentException If parent is null, the - * GraphicsConfiguration is not a screen device or - * GraphicsEnvironment.isHeadless() returns true. - * - * @since 1.4 - */ -public -Dialog (Dialog parent, String title, boolean modal, GraphicsConfiguration gc) -{ - super (parent, parent.getGraphicsConfiguration ()); + /** + * @serial Indicates whether or not this dialog box is resizable. + */ + private boolean resizable = true; - // A null title is equivalent to an empty title - this.title = (title != null) ? title : ""; - this.modal = modal; - visible = false; + /** + * @serial The title string for this dialog box, which can be + * <code>null</code>. + */ + private String title; - setLayout (new BorderLayout ()); -} + /** + * This field indicates whether the dialog is undecorated or not. + */ + private boolean undecorated = false; -/*************************************************************************/ + /** + * Indicates that we are blocked for modality in show + */ + private boolean blocked = false; -/* - * Instance Variables - */ + /** + * Secondary EventQueue to handle AWT events while we are blocked for + * modality in show. + */ + private EventQueue eq2 = null; -/** - * Returns the title of this dialog box. - * - * @return The title of this dialog box. - */ -public String -getTitle() -{ - return(title); -} + /** + * Initializes a new instance of <code>Dialog</code> with the specified + * parent, that is resizable and not modal, and which has no title. + * + * @param parent The parent frame of this dialog box. + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent) + { + this(parent, "", false); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>Dialog</code> with the specified + * parent and modality, that is resizable and which has no title. + * + * @param parent The parent frame of this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent, boolean modal) + { + this(parent, "", modal); + } -/** - * Sets the title of this dialog box to the specified string. - * - * @param title The new title. - */ -public synchronized void -setTitle(String title) -{ - // A null title is equivalent to an empty title - this.title = (title != null) ? title : ""; + /** + * Initializes a new instance of <code>Dialog</code> with the specified + * parent, that is resizable and not modal, and which has the specified + * title. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * + * @exception IllegalArgumentException If the owner's GraphicsConfiguration + * is not from a screen device, or if owner is null. This exceptionnis + * always thrown when GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent, String title) + { + this(parent, title, false); + } - if (peer != null) - { - DialogPeer d = (DialogPeer) peer; - d.setTitle (title); - } -} + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title, and modality, that is resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * + * @exception IllegalArgumentException If owner is null or + * GraphicsEnvironment.isHeadless() returns true. + */ + public Dialog(Frame parent, String title, boolean modal) + { + this(parent, title, modal, parent.getGraphicsConfiguration()); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title, modality and <code>GraphicsConfiguration</code>, that is + * resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * @param gc The <code>GraphicsConfiguration</code> object to use. If + * <code>null</code> the <code>GraphicsConfiguration</code> of the target + * frame is used. + * + * @exception IllegalArgumentException If owner is null, the + * GraphicsConfiguration is not a screen device or + * GraphicsEnvironment.isHeadless() returns true. + * @since 1.4 + */ + public Dialog(Frame parent, String title, boolean modal, + GraphicsConfiguration gc) + { + super(parent, (gc == null) ? parent.getGraphicsConfiguration() : gc); -/** - * Tests whether or not this dialog box is modal. - * - * @return <code>true</code> if this dialog box is modal, - * <code>false</code> otherwise. - */ -public boolean -isModal() -{ - return(modal); -} + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + this.modal = modal; + visible = false; -/*************************************************************************/ + setLayout(new BorderLayout()); + } -/** - * Changes the modality of this dialog box. This can only be done before - * the peer is created. - * - * @param modal <code>true</code> to make this dialog box modal, - * <code>false</code> to make it non-modal. - */ -public void -setModal(boolean modal) -{ - this.modal = modal; -} + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, that is resizable. + * + * @param owner The parent frame of this dialog box. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.2 + */ + public Dialog(Dialog owner) + { + this(owner, "", false, owner.getGraphicsConfiguration()); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent and title, that is resizable. + * + * @param owner The parent frame of this dialog box. + * @param title The title string for this dialog box. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns + * true. + * @since 1.2 + */ + public Dialog(Dialog owner, String title) + { + this(owner, title, false, owner.getGraphicsConfiguration()); + } -/** - * Tests whether or not this dialog box is resizable. - * - * @return <code>true</code> if this dialog is resizable, <code>false</code>, - * otherwise. - */ -public boolean -isResizable() -{ - return(resizable); -} + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title and modality, that is resizable. + * + * @param owner The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * + * @exception IllegalArgumentException If parent is null. This exception is + * always thrown when GraphicsEnvironment.isHeadless() returns true. + * @since 1.2 + */ + public Dialog(Dialog owner, String title, boolean modal) + { + this(owner, title, modal, owner.getGraphicsConfiguration()); + } -/*************************************************************************/ + /** + * Initializes a new instance of <code>Dialog</code> with the specified, + * parent, title, modality and <code>GraphicsConfiguration</code>, that is + * resizable. + * + * @param parent The parent frame of this dialog box. + * @param title The title string for this dialog box. + * @param modal <code>true</code> if this dialog box is modal, + * <code>false</code> otherwise. + * @param gc The <code>GraphicsConfiguration</code> object to use. If + * <code>null</code> the <code>GraphicsConfiguration</code> of the target + * frame is used. + * + * @exception IllegalArgumentException If parent is null, the + * GraphicsConfiguration is not a screen device or + * GraphicsEnvironment.isHeadless() returns true. + * + * @since 1.4 + */ + public Dialog(Dialog parent, String title, boolean modal, + GraphicsConfiguration gc) + { + super(parent, (gc == null) ? parent.getGraphicsConfiguration() : gc); -/** - * Changes the resizability of this dialog box. - * - * @param resizable <code>true</code> to make this dialog resizable, - * <code>false</code> to make it non-resizable. - */ -public synchronized void -setResizable(boolean resizable) -{ - this.resizable = resizable; - if (peer != null) - { - DialogPeer d = (DialogPeer) peer; - d.setResizable (resizable); - } -} + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + this.modal = modal; + visible = false; -/*************************************************************************/ + setLayout(new BorderLayout()); + } -/** - * Creates this object's native peer. - */ -public synchronized void -addNotify() -{ - if (peer == null) - peer = getToolkit ().createDialog (this); - super.addNotify (); -} + /** + * Returns the title of this dialog box. + * + * @return The title of this dialog box. + */ + public String getTitle() + { + return title; + } -/*************************************************************************/ + /** + * Sets the title of this dialog box to the specified string. + * + * @param title the new title. If <code>null</code> an empty + * title will be set. + */ + public synchronized void setTitle(String title) + { + // A null title is equivalent to an empty title + this.title = (title != null) ? title : ""; + + if (peer != null) + { + DialogPeer d = (DialogPeer) peer; + d.setTitle(title); + } + } -/** - * Makes this dialog visible and brings it to the front. - * If the dialog is modal and is not already visible, this call will not - * return until the dialog is hidden by someone calling hide or dispose. - * If this is the event dispatching thread we must ensure that another event - * thread runs while the one which invoked this method is blocked. - */ -public synchronized void -show() -{ - super.show(); - - if (isModal()) - { - // If already shown (and blocked) just return - if (blocked) - return; - - /* If show is called in the dispatch thread for a modal dialog it will - block so we must run another thread so the events keep being - dispatched.*/ - if (EventQueue.isDispatchThread ()) - { - EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); - eq2 = new EventQueue (); - eq.push (eq2); - } - - try - { - blocked = true; - wait (); - blocked = false; - } - catch (InterruptedException e) - { - blocked = false; - } - - if (eq2 != null) - { - eq2.pop (); - eq2 = null; - } - } -} + /** + * Tests whether or not this dialog box is modal. + * + * @return <code>true</code> if this dialog box is modal, <code>false</code> + * otherwise. + */ + public boolean isModal() + { + return modal; + } -/*************************************************************************/ + /** + * Changes the modality of this dialog box. This can only be done before the + * peer is created. + * + * @param modal <code>true</code> to make this dialog box modal, + * <code>false</code> to make it non-modal. + */ + public void setModal(boolean modal) + { + this.modal = modal; + } -/** - * Hides the Dialog and then - * causes show() to return if it is currently blocked. - */ + /** + * Tests whether or not this dialog box is resizable. + * + * @return <code>true</code> if this dialog is resizable, + * <code>false</code> otherwise. + */ + public boolean isResizable() + { + return resizable; + } -public synchronized void -hide () -{ - if (blocked) - { - notifyAll (); - } + /** + * Changes the resizability of this dialog box. + * + * @param resizable <code>true</code> to make this dialog resizable, + * <code>false</code> to make it non-resizable. + */ + public synchronized void setResizable(boolean resizable) + { + this.resizable = resizable; + if (peer != null) + { + DialogPeer d = (DialogPeer) peer; + d.setResizable(resizable); + } + } - super.hide(); -} + /** + * Creates this object's native peer. + */ + public synchronized void addNotify() + { + if (peer == null) + peer = getToolkit().createDialog(this); + super.addNotify(); + } -/*************************************************************************/ + /** + * Makes this dialog visible and brings it to the front. If the dialog is + * modal and is not already visible, this call will not return until the + * dialog is hidden by someone calling hide or dispose. If this is the event + * dispatching thread we must ensure that another event thread runs while the + * one which invoked this method is blocked. + * + * @deprecated Use {@link Component#setVisible(boolean)} instead. + */ + public synchronized void show() + { + super.show(); + + if (isModal()) + { + // If already shown (and blocked) just return + if (blocked) + return; + + /* + * If show is called in the dispatch thread for a modal dialog it will + * block so we must run another thread so the events keep being + * dispatched. + */ + if (EventQueue.isDispatchThread()) + { + EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue(); + eq2 = new EventQueue(); + eq.push(eq2); + } + + try + { + blocked = true; + wait(); + blocked = false; + } + catch (InterruptedException e) + { + blocked = false; + } + + if (eq2 != null) + { + eq2.pop(); + eq2 = null; + } + } + } -/** - * Disposes the Dialog and then causes show() to return - * if it is currently blocked. - */ + /** + * Hides the Dialog and then causes show() to return if it is currently + * blocked. + * + * @deprecated Use {@link Component#setVisible(boolean)} instead. + */ + public synchronized void hide() + { + if (blocked) + { + notifyAll(); + } -public synchronized void -dispose () -{ - if (blocked) - { - notifyAll (); - } + super.hide(); + } - super.dispose(); -} + /** + * Disposes the Dialog and then causes show() to return if it is currently + * blocked. + */ + public synchronized void dispose() + { + if (blocked) + { + notifyAll(); + } -/*************************************************************************/ + super.dispose(); + } -/** - * Returns a debugging string for this component. - * - * @return A debugging string for this component. - */ -protected String -paramString() -{ - return ("title+" + title + ",modal=" + modal + - ",resizable=" + resizable + "," + super.paramString()); -} + /** + * Returns a debugging string for this component. + * + * @return A debugging string for this component. + */ + protected String paramString() + { + return "title+" + title + ",modal=" + modal + ",resizable=" + resizable + + "," + super.paramString(); + } /** * Returns whether this frame is undecorated or not. * + * @return <code>true</code> if this dialog is undecorated, + * <code>false</code> otherwise. + * * @since 1.4 */ - public boolean isUndecorated () + public boolean isUndecorated() { return undecorated; } @@ -505,28 +471,42 @@ paramString() * Disables or enables decorations for this frame. This method can only be * called while the frame is not displayable. * - * @exception IllegalComponentStateException If this frame is displayable. + * @param undecorated <code>true</code> to disable dialog decorations, + * <code>false</code> otherwise. * + * @exception IllegalComponentStateException If this frame is displayable. * @since 1.4 */ - public void setUndecorated (boolean undecorated) + public void setUndecorated(boolean undecorated) { - if (isDisplayable ()) - throw new IllegalComponentStateException (); + if (isDisplayable()) + throw new IllegalComponentStateException(); this.undecorated = undecorated; } - - protected class AccessibleAWTDialog extends AccessibleAWTWindow + + /** + * Accessibility support for <code>Dialog</code>. + */ + protected class AccessibleAWTDialog + extends AccessibleAWTWindow { private static final long serialVersionUID = 4837230331833941201L; + /** + * Gets the role of this object. + * @return AccessibleRole.DIALOG + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.DIALOG; } - - public AccessibleStateSet getAccessibleState() + + /** + * Gets the state set of this object. + * @return The current state of this dialog. + */ + public AccessibleStateSet getAccessibleStateSet() { AccessibleStateSet states = super.getAccessibleStateSet(); if (isResizable()) @@ -536,11 +516,11 @@ paramString() return states; } } - + /** - * Gets the AccessibleContext associated with this <code>Dialog</code>. - * The context is created, if necessary. - * + * Gets the AccessibleContext associated with this <code>Dialog</code>. The + * context is created, if necessary. + * * @return the associated context */ public AccessibleContext getAccessibleContext() @@ -551,5 +531,4 @@ paramString() return accessibleContext; } -} // class Dialog - +} diff --git a/libjava/classpath/java/awt/Frame.java b/libjava/classpath/java/awt/Frame.java index 7003dac..5420136 100644 --- a/libjava/classpath/java/awt/Frame.java +++ b/libjava/classpath/java/awt/Frame.java @@ -614,16 +614,27 @@ public class Frame extends Window implements MenuContainer return next_frame_number++; } + /** + * Accessibility support for <code>Frame</code>. + */ protected class AccessibleAWTFrame extends AccessibleAWTWindow { private static final long serialVersionUID = -6172960752956030250L; + /** + * Gets the role of this object. + * @return AccessibleRole.FRAME + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.FRAME; } - public AccessibleStateSet getAccessibleState() + /** + * Gets the state set of this object. + * @return The current state of this frame. + */ + public AccessibleStateSet getAccessibleStateSet() { AccessibleStateSet states = super.getAccessibleStateSet(); if (isResizable()) diff --git a/libjava/classpath/java/awt/GraphicsConfiguration.java b/libjava/classpath/java/awt/GraphicsConfiguration.java index 1526ad3..f68a1e6 100644 --- a/libjava/classpath/java/awt/GraphicsConfiguration.java +++ b/libjava/classpath/java/awt/GraphicsConfiguration.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt; +import gnu.classpath.NotImplementedException; + import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; @@ -216,6 +218,7 @@ public abstract class GraphicsConfiguration * @since 1.4 */ public BufferCapabilities getBufferCapabilities() + throws NotImplementedException { throw new Error("not implemented"); } @@ -227,6 +230,7 @@ public abstract class GraphicsConfiguration * @since 1.4 */ public ImageCapabilities getImageCapabilities() + throws NotImplementedException { throw new Error("not implemented"); } diff --git a/libjava/classpath/java/awt/GridBagLayout.java b/libjava/classpath/java/awt/GridBagLayout.java index 714e080..f827d21 100644 --- a/libjava/classpath/java/awt/GridBagLayout.java +++ b/libjava/classpath/java/awt/GridBagLayout.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt; +import gnu.classpath.NotImplementedException; + import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; @@ -323,6 +325,7 @@ public class GridBagLayout * Obsolete. */ protected void AdjustForGravity (GridBagConstraints gbc, Rectangle rect) + throws NotImplementedException { // FIXME throw new Error ("Not implemented"); @@ -349,107 +352,121 @@ public class GridBagLayout // be invalidated, clearing the layout information cache, // layoutInfo. So we wait until after this for loop to set // layoutInfo. - for(int i = 0; i < components.length; i++) - { - Component component = components [i]; - - // If component is not visible we dont have to care about it. - if (!component.isVisible()) - continue; - - GridBagConstraints constraints = - lookupInternalConstraints(component); - - int cellx = sumIntArray(info.colWidths, constraints.gridx); - int celly = sumIntArray(info.rowHeights, constraints.gridy); - int cellw = sumIntArray(info.colWidths, - constraints.gridx + constraints.gridwidth) - cellx; - int cellh = sumIntArray(info.rowHeights, - constraints.gridy + constraints.gridheight) - celly; - - Insets insets = constraints.insets; - if (insets != null) - { - cellx += insets.left; - celly += insets.top; - cellw -= insets.left + insets.right; - cellh -= insets.top + insets.bottom; - } - - Dimension dim = component.getPreferredSize(); - - // Note: Documentation says that padding is added on both sides, but - // visual inspection shows that the Sun implementation only adds it - // once, so we do the same. - dim.width += constraints.ipadx; - dim.height += constraints.ipady; - - switch(constraints.fill) - { - case GridBagConstraints.HORIZONTAL: - dim.width = cellw; - break; - case GridBagConstraints.VERTICAL: - dim.height = cellh; - break; - case GridBagConstraints.BOTH: - dim.width = cellw; - dim.height = cellh; - break; - } - - int x; - int y; - - switch(constraints.anchor) - { - case GridBagConstraints.NORTH: - x = cellx + (cellw - dim.width) / 2; - y = celly; - break; - case GridBagConstraints.SOUTH: - x = cellx + (cellw - dim.width) / 2; - y = celly + cellh - dim.height; - break; - case GridBagConstraints.WEST: - x = cellx; - y = celly + (cellh - dim.height) / 2; - break; - case GridBagConstraints.EAST: - x = cellx + cellw - dim.width; - y = celly + (cellh - dim.height) / 2; - break; - case GridBagConstraints.NORTHEAST: - x = cellx + cellw - dim.width; - y = celly; - break; - case GridBagConstraints.NORTHWEST: - x = cellx; - y = celly; - break; - case GridBagConstraints.SOUTHEAST: - x = cellx + cellw - dim.width; - y = celly + cellh - dim.height; - break; - case GridBagConstraints.SOUTHWEST: - x = cellx; - y = celly + cellh - dim.height; - break; - default: - x = cellx + (cellw - dim.width) / 2; - y = celly + (cellh - dim.height) / 2; - break; - } - - component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, dim.height); - } - - // DEBUG - //dumpLayoutInfo (info); - - // Cache layout information. - layoutInfo = getLayoutInfo (parent, PREFERREDSIZE); - } + Component lastComp = null; + int cellx = 0; + int celly = 0; + int cellw = 0; + int cellh = 0; + for (int i = 0; i < components.length; i++) + { + Component component = components[i]; + + // If component is not visible we dont have to care about it. + if (! component.isVisible()) + continue; + + Dimension dim = component.getPreferredSize(); + GridBagConstraints constraints = lookupInternalConstraints(component); + + if (lastComp != null + && constraints.gridheight == GridBagConstraints.REMAINDER) + celly += cellh; + else + celly = sumIntArray(info.rowHeights, constraints.gridy); + + if (lastComp != null + && constraints.gridwidth == GridBagConstraints.REMAINDER) + cellx += cellw; + else + cellx = sumIntArray(info.colWidths, constraints.gridx); + + cellw = sumIntArray(info.colWidths, constraints.gridx + + constraints.gridwidth) - cellx; + cellh = sumIntArray(info.rowHeights, constraints.gridy + + constraints.gridheight) - celly; + + Insets insets = constraints.insets; + if (insets != null) + { + cellx += insets.left; + celly += insets.top; + cellw -= insets.left + insets.right; + cellh -= insets.top + insets.bottom; + } + + // Note: Documentation says that padding is added on both sides, but + // visual inspection shows that the Sun implementation only adds it + // once, so we do the same. + dim.width += constraints.ipadx; + dim.height += constraints.ipady; + + switch (constraints.fill) + { + case GridBagConstraints.HORIZONTAL: + dim.width = cellw; + break; + case GridBagConstraints.VERTICAL: + dim.height = cellh; + break; + case GridBagConstraints.BOTH: + dim.width = cellw; + dim.height = cellh; + break; + } + + int x = 0; + int y = 0; + + switch (constraints.anchor) + { + case GridBagConstraints.NORTH: + x = cellx + (cellw - dim.width) / 2; + y = celly; + break; + case GridBagConstraints.SOUTH: + x = cellx + (cellw - dim.width) / 2; + y = celly + cellh - dim.height; + break; + case GridBagConstraints.WEST: + x = cellx; + y = celly + (cellh - dim.height) / 2; + break; + case GridBagConstraints.EAST: + x = cellx + cellw - dim.width; + y = celly + (cellh - dim.height) / 2; + break; + case GridBagConstraints.NORTHEAST: + x = cellx + cellw - dim.width; + y = celly; + break; + case GridBagConstraints.NORTHWEST: + x = cellx; + y = celly; + break; + case GridBagConstraints.SOUTHEAST: + x = cellx + cellw - dim.width; + y = celly + cellh - dim.height; + break; + case GridBagConstraints.SOUTHWEST: + x = cellx; + y = celly + cellh - dim.height; + break; + default: + x = cellx + (cellw - dim.width) / 2; + y = celly + (cellh - dim.height) / 2; + break; + } + component.setBounds(info.pos_x + x, info.pos_y + y, dim.width, + dim.height); + lastComp = component; + } + + // DEBUG + //dumpLayoutInfo(info); + + // Cache layout information. + layoutInfo = getLayoutInfo(parent, PREFERREDSIZE); + } /** * Obsolete. @@ -485,11 +502,10 @@ public class GridBagLayout for (int i = 0; i < components.length; i++) { Component component = components [i]; - // If component is not visible we dont have to care about it. if (!component.isVisible()) continue; - + // When looking up the constraint for the first time, check the // original unmodified constraint. After the first time, always // refer to the internal modified constraint. @@ -516,7 +532,6 @@ public class GridBagLayout // // nothing to check; just add it - // cases 1 and 2 if(constraints.gridx == GridBagConstraints.RELATIVE) { @@ -560,7 +575,9 @@ public class GridBagLayout // this column. We want to add this component below it. // If this column is empty, add to the 0 position. if (!lastInCol.containsKey(new Integer(constraints.gridx))) - y = 0; + { + y = current_y; + } else { Component lastComponent = (Component)lastInCol.get(new Integer(constraints.gridx)); @@ -596,7 +613,7 @@ public class GridBagLayout // Update our reference points for RELATIVE gridx and gridy. if(constraints.gridwidth == GridBagConstraints.REMAINDER) { - current_y = constraints.gridy + Math.max(1, constraints.gridheight); + current_y = constraints.gridy + Math.max(1, constraints.gridheight); } else if (constraints.gridwidth != GridBagConstraints.REMAINDER) { @@ -788,7 +805,7 @@ public class GridBagLayout height += constraints.insets.top + constraints.insets.bottom; height += constraints.ipady; - + distributeSizeAndWeight(height, constraints.weighty, constraints.gridy, @@ -918,7 +935,7 @@ public class GridBagLayout sizes[start] = Math.max(sizes[start], size); weights[start] = Math.max(weights[start], weight); } - else if (span > 1) + else { int numOccupied = span; int lastOccupied = -1; diff --git a/libjava/classpath/java/awt/Image.java b/libjava/classpath/java/awt/Image.java index 93c2c47..6ade302 100644 --- a/libjava/classpath/java/awt/Image.java +++ b/libjava/classpath/java/awt/Image.java @@ -166,6 +166,8 @@ public abstract class Image * loading will be produced according to the hints of the algorithm * requested. If either the width or height is non-positive, it is adjusted * to preserve the original aspect ratio. + * If an illegal value of <code>flags</code> is passed, + * the default algorithm is used. * * @param width the width of the scaled image * @param height the height of the scaled image @@ -183,18 +185,15 @@ public abstract class Image ImageFilter filter; switch (flags) { - case SCALE_DEFAULT: - case SCALE_FAST: - case SCALE_REPLICATE: - filter = new ReplicateScaleFilter(width, height); - break; case SCALE_AREA_AVERAGING: + case SCALE_SMOOTH: filter = new AreaAveragingScaleFilter(width, height); break; - case SCALE_SMOOTH: - throw new Error("SCALE_SMOOTH: not implemented"); + case SCALE_DEFAULT: + case SCALE_FAST: + case SCALE_REPLICATE: default: - throw new Error("Unknown flag or not implemented: " + flags); + filter = new ReplicateScaleFilter(width, height); } ImageProducer producer = new FilteredImageSource(getSource(), filter); diff --git a/libjava/classpath/java/awt/LightweightDispatcher.java b/libjava/classpath/java/awt/LightweightDispatcher.java index 6573b12..8606464 100644 --- a/libjava/classpath/java/awt/LightweightDispatcher.java +++ b/libjava/classpath/java/awt/LightweightDispatcher.java @@ -110,14 +110,12 @@ class LightweightDispatcher */ public boolean dispatchEvent(AWTEvent event) { - boolean dispatched = false; if (event instanceof MouseEvent && event.getSource() instanceof Window) { MouseEvent mouseEvent = (MouseEvent) event; - handleMouseEvent(mouseEvent); - dispatched = true; + return handleMouseEvent(mouseEvent); } - return dispatched; + return false; } /** @@ -125,12 +123,14 @@ class LightweightDispatcher * (Window instances) and dispatches them to the correct lightweight child. * * @param ev the mouse event + * @return whether or not we found a lightweight that handled the event. */ - private void handleMouseEvent(MouseEvent ev) + private boolean handleMouseEvent(MouseEvent ev) { Window window = (Window) ev.getSource(); Component target = window.findComponentAt(ev.getX(), ev.getY()); - if (target != null && target.isLightweight()) + target = findTarget(target); + if (target == null || target.isLightweight()) { // Dispatch additional MOUSE_EXITED and MOUSE_ENTERED if event target // is different from the last event target. @@ -146,13 +146,16 @@ class LightweightDispatcher ev.getClickCount(), ev.isPopupTrigger()); lastTarget.dispatchEvent(mouseExited); } - Point p = AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), - target); - MouseEvent mouseEntered = - new MouseEvent(target, MouseEvent.MOUSE_ENTERED, ev.getWhen(), - ev.getModifiers(), p.x, p.y, ev.getClickCount(), - ev.isPopupTrigger()); - target.dispatchEvent(mouseEntered); + if (target != null) + { + Point p = AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), + target); + MouseEvent mouseEntered = + new MouseEvent(target, MouseEvent.MOUSE_ENTERED, ev.getWhen(), + ev.getModifiers(), p.x, p.y, ev.getClickCount(), + ev.isPopupTrigger()); + target.dispatchEvent(mouseEntered); + } } switch (ev.getID()) @@ -183,18 +186,43 @@ class LightweightDispatcher lastTarget = target; - Point targetCoordinates = - AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), target); - int dx = targetCoordinates.x - ev.getX(); - int dy = targetCoordinates.y - ev.getY(); - ev.translatePoint(dx, dy); - ev.setSource(target); - target.dispatchEvent(ev); - - // We reset the event, so that the normal event dispatching is not - // influenced by this modified event. - ev.setSource(window); - ev.translatePoint(-dx, -dy); + if (target != null) + { + Point targetCoordinates = + AWTUtilities.convertPoint(window, ev.getX(), ev.getY(), target); + int dx = targetCoordinates.x - ev.getX(); + int dy = targetCoordinates.y - ev.getY(); + ev.translatePoint(dx, dy); + ev.setSource(target); + target.dispatchEvent(ev); + // We reset the event, so that the normal event dispatching is not + // influenced by this modified event. + ev.setSource(window); + ev.translatePoint(-dx, -dy); + } + + return true; + } + else + return false; + } + + /** + * Finds the actual target for a mouseevent, starting at <code>c</code>. + * This searches upwards the component hierarchy until it finds a component + * that has a mouselistener attached. + * + * @param c the component to start searching from + * + * @return the actual receiver of the mouse event + */ + private Component findTarget(Component c) + { + Component target = c; + while (target != null && target.getMouseListeners().length == 0) + { + target = target.getParent(); } + return target; } } diff --git a/libjava/classpath/java/awt/List.java b/libjava/classpath/java/awt/List.java index 00636a0..b28e201 100644 --- a/libjava/classpath/java/awt/List.java +++ b/libjava/classpath/java/awt/List.java @@ -446,7 +446,7 @@ preferredSize(int rows) if (peer != null) return peer.preferredSize (rows); else - return new Dimension (0, 0); + return getSize(); } /*************************************************************************/ diff --git a/libjava/classpath/java/awt/MediaTracker.java b/libjava/classpath/java/awt/MediaTracker.java index 9abfde6..8792e1d 100644 --- a/libjava/classpath/java/awt/MediaTracker.java +++ b/libjava/classpath/java/awt/MediaTracker.java @@ -634,7 +634,8 @@ public class MediaTracker implements java.io.Serializable else prev.next = e.next; } - prev = e; + else + prev = e; e = e.next; } } diff --git a/libjava/classpath/java/awt/MenuItem.java b/libjava/classpath/java/awt/MenuItem.java index 3e39d11..a7ac796 100644 --- a/libjava/classpath/java/awt/MenuItem.java +++ b/libjava/classpath/java/awt/MenuItem.java @@ -111,7 +111,7 @@ private transient ActionListener action_listeners; private static final long serialVersionUID = -217847831945965825L; /** Constructor */ - public AccessibleAWTMenuItem() + protected AccessibleAWTMenuItem() { super(); } diff --git a/libjava/classpath/java/awt/ScrollPaneAdjustable.java b/libjava/classpath/java/awt/ScrollPaneAdjustable.java index bec5b51..21b58c3 100644 --- a/libjava/classpath/java/awt/ScrollPaneAdjustable.java +++ b/libjava/classpath/java/awt/ScrollPaneAdjustable.java @@ -178,7 +178,16 @@ public class ScrollPaneAdjustable public String paramString () { - throw new Error ("not implemented"); + return ("scrollpane=" + sp + ", orientation=" + orientation + + ", value=" + value + ", minimum=" + minimum + + ", maximum=" + maximum + ", visibleAmount=" + visibleAmount + + ", unitIncrement=" + unitIncrement + + ", blockIncrement=" + blockIncrement); + } + + public String toString() + { + return getClass().getName() + "[" + paramString() + "]"; } /** diff --git a/libjava/classpath/java/awt/TexturePaint.java b/libjava/classpath/java/awt/TexturePaint.java index a12e384..57d7574 100644 --- a/libjava/classpath/java/awt/TexturePaint.java +++ b/libjava/classpath/java/awt/TexturePaint.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt; +import gnu.classpath.NotImplementedException; + import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; @@ -65,10 +67,12 @@ public class TexturePaint implements Paint Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) + throws NotImplementedException { throw new Error("not implemented"); } public int getTransparency() + throws NotImplementedException { throw new Error("not implemented"); } diff --git a/libjava/classpath/java/awt/Toolkit.java b/libjava/classpath/java/awt/Toolkit.java index e2a4bc9..16f1caf 100644 --- a/libjava/classpath/java/awt/Toolkit.java +++ b/libjava/classpath/java/awt/Toolkit.java @@ -1,5 +1,5 @@ /* Toolkit.java -- AWT Toolkit superclass - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,6 +39,7 @@ exception statement from your version. */ package java.awt; +import gnu.classpath.SystemProperties; import gnu.java.awt.peer.GLightweightPeer; import java.awt.datatransfer.Clipboard; @@ -78,10 +79,15 @@ import java.awt.peer.TextFieldPeer; import java.awt.peer.WindowPeer; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.File; +import java.io.FileInputStream; import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Map; import java.util.Properties; +import java.util.StringTokenizer; /** * The AWT system uses a set of native peer objects to implement its @@ -525,16 +531,27 @@ public abstract class Toolkit { if (toolkit != null) return toolkit; - String toolkit_name = System.getProperty("awt.toolkit", - default_toolkit_name); + String toolkit_name = SystemProperties.getProperty("awt.toolkit", + default_toolkit_name); try { - Class cls = Class.forName(toolkit_name); + ClassLoader cl; + cl = (ClassLoader) AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + return ClassLoader.getSystemClassLoader(); + } + }); + Class cls = cl.loadClass(toolkit_name); Object obj = cls.newInstance(); if (!(obj instanceof Toolkit)) throw new AWTError(toolkit_name + " is not a subclass of " + "java.awt.Toolkit"); toolkit = (Toolkit) obj; + + initAccessibility(); return toolkit; } catch (ThreadDeath death) @@ -696,9 +713,18 @@ public abstract class Toolkit public abstract Clipboard getSystemClipboard(); /** - * Gets the singleton instance of the system selection as a Clipboard object. + * Gets the singleton instance of the system selection as a + * Clipboard object. The system selection contains the selected text + * of the last component/widget that had focus and a text selection. + * The default implementation returns null. * - * @exception HeadlessException If GraphicsEnvironment.isHeadless() is true. + * @return The Clipboard holding the system (text) selection or null + * if the Toolkit or system doesn't support a selection clipboard. + * + * @exception HeadlessException If GraphicsEnvironment.isHeadless() + * is true. + * @exception SecurityException If the current security manager + * checkSystemClipboardAccess() doesn't allow access. * * @since 1.4 */ @@ -1206,4 +1232,138 @@ public abstract class Toolkit * @since 1.3 */ public abstract Map mapInputMethodHighlight(InputMethodHighlight highlight); + + /** + * Initializes the accessibility framework. In particular, this loads the + * properties javax.accessibility.screen_magnifier_present and + * javax.accessibility.screen_reader_present and loads + * the classes specified in javax.accessibility.assistive_technologies. + */ + private static void initAccessibility() + { + AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + Properties props = new Properties(); + String sep = File.separator; + + // Try the user configuration. + try + { + File propsFile = new File(System.getProperty("user.home") + sep + + ".accessibility.properties"); + FileInputStream in = new FileInputStream(propsFile); + props.load(in); + in.close(); + } + catch (Exception ex) + { + // User configuration not present, ignore. + } + + // Try the system configuration if there was no user configuration. + if (props.size() == 0) + { + try + { + File propsFile = + new File(System.getProperty("gnu.classpath.home.url") + + sep + "accessibility.properties"); + FileInputStream in = new FileInputStream(propsFile); + props.load(in); + in.close(); + } + catch (Exception ex) + { + // System configuration not present, ignore. + } + } + + // Fetch the screen_magnifier_present property. Check systen properties + // first, then fallback to the configuration file. + String magPresent = SystemProperties.getProperty + ("javax.accessibility.screen_magnifier_present"); + if (magPresent == null) + { + magPresent = props.getProperty("screen_magnifier_present"); + if (magPresent != null) + { + SystemProperties.setProperty + ("javax.accessibility.screen_magnifier_present", magPresent); + } + } + + // Fetch the screen_reader_present property. Check systen properties + // first, then fallback to the configuration file. + String readerPresent = SystemProperties.getProperty + ("javax.accessibility.screen_reader_present"); + if (readerPresent == null) + { + readerPresent = props.getProperty("screen_reader_present"); + if (readerPresent != null) + { + SystemProperties.setProperty + ("javax.accessibility.screen_reader_present", readerPresent); + } + } + + // Fetch the list of classes to be loaded. + String classes = SystemProperties.getProperty + ("javax.accessibility.assistive_technologies"); + if (classes == null) + { + classes = props.getProperty("assistive_technologies"); + if (classes != null) + { + SystemProperties.setProperty + ("javax.accessibility.assistive_technologies", classes); + } + } + + // Try to load the assisitive_technologies classes. + if (classes != null) + { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + StringTokenizer tokenizer = new StringTokenizer(classes, ","); + while (tokenizer.hasMoreTokens()) + { + String className = tokenizer.nextToken(); + try + { + Class atClass = cl.loadClass(className); + atClass.newInstance(); + } + catch (ClassNotFoundException ex) + { + AWTError err = new AWTError("Assistive Technology class not" + + " found: " + className); + err.initCause(ex); + throw err; + } + catch (InstantiationException ex) + { + AWTError err = + new AWTError("Assistive Technology class cannot be " + + "instantiated: " + className); + err.initCause(ex); + throw err; + } + catch (IllegalAccessException ex) + { + AWTError err = + new AWTError("Assistive Technology class cannot be " + + "accessed: " + className); + err.initCause(err); + throw err; + } + } + } + return null; + } + }); + + } + } // class Toolkit diff --git a/libjava/classpath/java/awt/Window.java b/libjava/classpath/java/awt/Window.java index 71a8d38..d9e90c0 100644 --- a/libjava/classpath/java/awt/Window.java +++ b/libjava/classpath/java/awt/Window.java @@ -1,5 +1,5 @@ /* Window.java -- - Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation + Copyright (C) 1999, 2000, 2002, 2003, 2004, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt; +import gnu.classpath.NotImplementedException; + import java.awt.event.ComponentEvent; import java.awt.event.FocusEvent; import java.awt.event.WindowAdapter; @@ -620,10 +622,25 @@ public class Window extends Container implements Accessible || windowStateListener != null || (eventMask & AWTEvent.WINDOW_EVENT_MASK) != 0)) processEvent(e); - else if (e.id == ComponentEvent.COMPONENT_RESIZED) - validate (); - else - super.dispatchEventImpl(e); + else + { + if (peer != null && (e.id == ComponentEvent.COMPONENT_RESIZED + || e.id == ComponentEvent.COMPONENT_MOVED)) + { + Rectangle bounds = peer.getBounds(); + x = bounds.x; + y = bounds.y; + height = bounds.height; + width = bounds.width; + + if (e.id == ComponentEvent.COMPONENT_RESIZED) + { + invalidate(); + validate(); + } + } + super.dispatchEventImpl(e); + } } /** @@ -1032,6 +1049,7 @@ public class Window extends Container implements Accessible * @deprecated */ public void applyResourceBundle(ResourceBundle rb) + throws NotImplementedException { throw new Error ("Not implemented"); } @@ -1143,6 +1161,47 @@ public class Window extends Container implements Accessible { this.focusableWindowState = focusableWindowState; } + + /** + * Check whether this Container is a focus cycle root. + * Returns always <code>true</code> as Windows are the + * root of the focus cycle. + * + * @return Always <code>true</code>. + * + * @since 1.4 + */ + public final boolean isFocusCycleRoot() + { + return true; + } + + /** + * Set whether or not this Container is the root of a focus + * traversal cycle. Windows are the root of the focus cycle + * and therefore this method does nothing. + * + * @param focusCycleRoot ignored. + * + * @since 1.4 + */ + public final void setFocusCycleRoot(boolean focusCycleRoot) + { + // calls to the method are ignored + } + + /** + * Returns the root container that owns the focus cycle where this + * component resides. Windows have no ancestors and this method + * returns always <code>null</code>. + * + * @return Always <code>null</code>. + * @since 1.4 + */ + public final Container getFocusCycleRootAncestor() + { + return null; + } /** * Generate a unique name for this window. diff --git a/libjava/classpath/java/awt/datatransfer/FlavorEvent.java b/libjava/classpath/java/awt/datatransfer/FlavorEvent.java index 8252dea..38b4818 100644 --- a/libjava/classpath/java/awt/datatransfer/FlavorEvent.java +++ b/libjava/classpath/java/awt/datatransfer/FlavorEvent.java @@ -45,6 +45,8 @@ import java.util.EventObject; * Fired by a ClipBoard for registered FlavorListeners. * * @author Mark J. Wielaard (mark@klomp.org) + * + * @since 1.5 */ public class FlavorEvent extends EventObject { diff --git a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java index 7b4d2fb..a80665a 100644 --- a/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java +++ b/libjava/classpath/java/awt/datatransfer/SystemFlavorMap.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.datatransfer; +import gnu.classpath.NotImplementedException; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -262,11 +264,13 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable * version of the native. */ public List getFlavorsForNative (String nat) + throws NotImplementedException { throw new Error ("Not implemented"); } public List getNativesForFlavor (DataFlavor flav) + throws NotImplementedException { throw new Error ("Not implemented"); } diff --git a/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java index 07b822e..37fde91 100644 --- a/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java +++ b/libjava/classpath/java/awt/dnd/DragGestureRecognizer.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.dnd; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Point; import java.awt.event.InputEvent; @@ -126,6 +128,7 @@ public abstract class DragGestureRecognizer implements Serializable } public void resetRecognizer() + throws NotImplementedException { throw new Error("not implemented"); } @@ -152,6 +155,7 @@ public abstract class DragGestureRecognizer implements Serializable } protected void fireDragGestureRecognized(int dragAction, Point p) + throws NotImplementedException { throw new Error("not implemented"); } diff --git a/libjava/classpath/java/awt/dnd/DragSourceContext.java b/libjava/classpath/java/awt/dnd/DragSourceContext.java index 2cf0d6d..88607b0 100644 --- a/libjava/classpath/java/awt/dnd/DragSourceContext.java +++ b/libjava/classpath/java/awt/dnd/DragSourceContext.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.dnd; +import gnu.classpath.NotImplementedException; + import java.awt.Component; import java.awt.Cursor; import java.awt.Image; @@ -86,6 +88,7 @@ public class DragSourceContext DragGestureEvent trigger, Cursor cursor, Image image, Point offset, Transferable trans, DragSourceListener dsl) + throws NotImplementedException { if (peer == null || trigger == null) @@ -130,6 +133,7 @@ public class DragSourceContext } public void setCursor (Cursor cursor) + throws NotImplementedException { this.cursor = cursor; // FIXME: Check if we need to do more here @@ -162,30 +166,37 @@ public class DragSourceContext } public void transferablesFlavorsChanged() + throws NotImplementedException { } public void dragEnter(DragSourceDragEvent e) + throws NotImplementedException { } public void dragOver(DragSourceDragEvent e) + throws NotImplementedException { } public void dragExit(DragSourceEvent e) + throws NotImplementedException { } public void dropActionChanged(DragSourceDragEvent e) + throws NotImplementedException { } public void dragDropEnd(DragSourceDropEvent e) + throws NotImplementedException { } public void dragMouseMoved(DragSourceDragEvent e) + throws NotImplementedException { } @@ -195,6 +206,7 @@ public class DragSourceContext } protected void updateCurrentCursor(int dropOp, int targetAct, int status) + throws NotImplementedException { } } // class DragSourceContext diff --git a/libjava/classpath/java/awt/dnd/DropTarget.java b/libjava/classpath/java/awt/dnd/DropTarget.java index 9fd7ef8..b0d4c2a 100644 --- a/libjava/classpath/java/awt/dnd/DropTarget.java +++ b/libjava/classpath/java/awt/dnd/DropTarget.java @@ -61,9 +61,7 @@ public class DropTarget */ private static final long serialVersionUID = -6283860791671019047L; - /** @specnote According to the online documentation, this is - * protected, but in reality it is public. */ - public static class DropTargetAutoScroller + protected static class DropTargetAutoScroller implements ActionListener { private Component component; diff --git a/libjava/classpath/java/awt/dnd/DropTargetContext.java b/libjava/classpath/java/awt/dnd/DropTargetContext.java index d1fb66e..19e27a9 100644 --- a/libjava/classpath/java/awt/dnd/DropTargetContext.java +++ b/libjava/classpath/java/awt/dnd/DropTargetContext.java @@ -54,9 +54,7 @@ public class DropTargetContext implements Serializable { static final long serialVersionUID = -634158968993743371L; - /** @specnote According to the online documentation, this is - * protected, but in reality it is public. */ - public class TransferableProxy implements Transferable + protected class TransferableProxy implements Transferable { protected boolean isLocal; protected Transferable transferable; diff --git a/libjava/classpath/java/awt/dnd/DropTargetEvent.java b/libjava/classpath/java/awt/dnd/DropTargetEvent.java index 56a4d48..f75f756 100644 --- a/libjava/classpath/java/awt/dnd/DropTargetEvent.java +++ b/libjava/classpath/java/awt/dnd/DropTargetEvent.java @@ -41,6 +41,8 @@ import java.util.EventObject; public class DropTargetEvent extends EventObject { + private static final long serialVersionUID = 2821229066521922993L; + protected DropTargetContext context; public DropTargetEvent (DropTargetContext context) diff --git a/libjava/classpath/java/awt/event/MouseEvent.java b/libjava/classpath/java/awt/event/MouseEvent.java index 3e0feca..f2bcfbc 100644 --- a/libjava/classpath/java/awt/event/MouseEvent.java +++ b/libjava/classpath/java/awt/event/MouseEvent.java @@ -402,7 +402,11 @@ public class MouseEvent extends InputEvent // FIXME: need a mauve test for this method if (modifiersEx != 0) s.append(",extModifiers=").append(getModifiersExText(modifiersEx)); - return s.append(",clickCount=").append(clickCount).toString(); + + s.append(",clickCount=").append(clickCount); + s.append(",consumed=").append(consumed); + + return s.toString(); } /** diff --git a/libjava/classpath/java/awt/font/GlyphMetrics.java b/libjava/classpath/java/awt/font/GlyphMetrics.java index 28b2088..18aaedc 100644 --- a/libjava/classpath/java/awt/font/GlyphMetrics.java +++ b/libjava/classpath/java/awt/font/GlyphMetrics.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.awt.geom.Rectangle2D; /** @@ -93,11 +95,13 @@ public final class GlyphMetrics } public float getLSB () + throws NotImplementedException { throw new Error ("not implemented"); } public float getRSB () + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/font/GlyphVector.java b/libjava/classpath/java/awt/font/GlyphVector.java index 57e2581..8d8a51d 100644 --- a/libjava/classpath/java/awt/font/GlyphVector.java +++ b/libjava/classpath/java/awt/font/GlyphVector.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.awt.Font; import java.awt.Rectangle; import java.awt.Shape; @@ -70,12 +72,14 @@ public abstract class GlyphVector implements Cloneable public abstract FontRenderContext getFontRenderContext (); public int getGlyphCharIndex (int glyphIndex) + throws NotImplementedException { throw new Error ("not implemented"); } public int[] getGlyphCharIndices (int beginGlyphIndex, int numEntries, int[] codeReturn) + throws NotImplementedException { throw new Error ("not implemented"); } @@ -95,12 +99,14 @@ public abstract class GlyphVector implements Cloneable public abstract Shape getGlyphOutline (int glyphIndex); public Shape getGlyphOutline (int glyphIndex, float x, float y) + throws NotImplementedException { throw new Error ("not implemented"); } public Rectangle getGlyphPixelBounds (int index, FontRenderContext renderFRC, float x, float y) + throws NotImplementedException { throw new Error ("not implemented"); } @@ -116,6 +122,7 @@ public abstract class GlyphVector implements Cloneable public abstract Shape getGlyphVisualBounds (int glyphIndex); public int getLayoutFlags () + throws NotImplementedException { throw new Error ("not implemented"); } @@ -130,6 +137,7 @@ public abstract class GlyphVector implements Cloneable public Rectangle getPixelBounds (FontRenderContext renderFRC, float x, float y) + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/font/GraphicAttribute.java b/libjava/classpath/java/awt/font/GraphicAttribute.java index 79eae99..107f16d 100644 --- a/libjava/classpath/java/awt/font/GraphicAttribute.java +++ b/libjava/classpath/java/awt/font/GraphicAttribute.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; @@ -71,6 +73,7 @@ public abstract class GraphicAttribute public abstract float getAscent (); public Rectangle2D getBounds () + throws NotImplementedException { throw new Error ("not implemented"); } @@ -78,6 +81,7 @@ public abstract class GraphicAttribute public abstract float getDescent (); public GlyphJustificationInfo getJustificationInfo () + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/font/ImageGraphicAttribute.java b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java index 77413f9..c050255 100644 --- a/libjava/classpath/java/awt/font/ImageGraphicAttribute.java +++ b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.Rectangle2D; @@ -57,6 +59,7 @@ public final class ImageGraphicAttribute extends GraphicAttribute public ImageGraphicAttribute (Image image, int alignment, float originX, float originY) + throws NotImplementedException { super (alignment); this.image = image; @@ -65,6 +68,7 @@ public final class ImageGraphicAttribute extends GraphicAttribute } public void draw (Graphics2D graphics, float x, float y) + throws NotImplementedException { throw new Error ("not implemented"); } @@ -78,31 +82,37 @@ public final class ImageGraphicAttribute extends GraphicAttribute } public boolean equals (ImageGraphicAttribute rhs) + throws NotImplementedException { throw new Error ("not implemented"); } public float getAdvance () + throws NotImplementedException { throw new Error ("not implemented"); } public float getAscent () + throws NotImplementedException { throw new Error ("not implemented"); } - public Rectangle2D getBounds () + public Rectangle2D getBounds () + throws NotImplementedException { throw new Error ("not implemented"); } public float getDescent () + throws NotImplementedException { throw new Error ("not implemented"); } public int hashCode () + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/font/LineBreakMeasurer.java b/libjava/classpath/java/awt/font/LineBreakMeasurer.java index 0a6a969..14985b4 100644 --- a/libjava/classpath/java/awt/font/LineBreakMeasurer.java +++ b/libjava/classpath/java/awt/font/LineBreakMeasurer.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.text.AttributedCharacterIterator; import java.text.BreakIterator; @@ -69,6 +71,7 @@ public final class LineBreakMeasurer public void deleteChar (AttributedCharacterIterator newParagraph, int deletePos) + throws NotImplementedException { throw new Error ("not implemented"); } @@ -80,28 +83,33 @@ public final class LineBreakMeasurer public void insertChar (AttributedCharacterIterator newParagraph, int insertPos) + throws NotImplementedException { throw new Error ("not implemented"); } public TextLayout nextLayout (float wrappingWidth) + throws NotImplementedException { throw new Error ("not implemented"); } public TextLayout nextLayout (float wrappingWidth, int offsetLimit, boolean requireNextWord) + throws NotImplementedException { throw new Error ("not implemented"); } public int nextOffset (float wrappingWidth) + throws NotImplementedException { throw new Error ("not implemented"); } public int nextOffset (float wrappingWidth, int offsetLimit, boolean requireNextWord) + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/font/NumericShaper.java b/libjava/classpath/java/awt/font/NumericShaper.java index efbdcd4..add1c6a 100644 --- a/libjava/classpath/java/awt/font/NumericShaper.java +++ b/libjava/classpath/java/awt/font/NumericShaper.java @@ -39,99 +39,387 @@ exception statement from your version. */ package java.awt.font; import java.io.Serializable; +import java.lang.Character.UnicodeBlock; /** + * This class handles numeric shaping. A shaper can either be contextual + * or not. A non-contextual shaper will always translate ASCII digits + * in its input into the target Unicode range. A contextual shaper will + * change the target Unicode range depending on the characters it has + * previously processed. + * * @author Michael Koch + * @author Tom Tromey + * * @since 1.4 + * @specnote This class does not handle LIMBU or OSMANYA. + * @specnote The JDK does not seem to properly handle ranges without a + * digit zero, such as TAMIL. This implementation does. */ public final class NumericShaper implements Serializable { private static final long serialVersionUID = -8022764705923730308L; - + + /** Convenience constant representing all the valid Unicode ranges. */ public static final int ALL_RANGES = 524287; + + /** + * Constant representing the Unicode ARABIC range. Shaping done + * using this range will translate to the arabic decimal characters. + * Use EASTERN_ARABIC if you want to shape to the eastern arabic + * (also known as the extended arabic) decimal characters. + */ public static final int ARABIC = 2; + + /** Constant representing the Unicode BENGALI range. */ public static final int BENGALI = 16; + + /** Constant representing the Unicode DEVANAGARI range. */ public static final int DEVANAGARI = 8; + + /** + * Constant representing the Unicode extended arabic range. + * In Unicode there are two different sets of arabic digits; + * this selects the extended or eastern set. + */ public static final int EASTERN_ARABIC = 4; + + /** + * Constant representing the Unicode ETHIOPIC range. Note that + * there is no digit zero in this range; an ASCII digit zero + * is left unchanged when shaping to this range. + */ public static final int ETHIOPIC = 65536; + + /** + * Constant representing the Unicode EUROPEAN range. For + * contextual shaping purposes, characters in the various + * extended Latin character blocks are recognized as EUROPEAN. + */ public static final int EUROPEAN = 1; + + /** Constant representing the Unicode GUJARATI range. */ public static final int GUJARATI = 64; + + /** Constant representing the Unicode GURMUKHI range. */ public static final int GURMUKHI = 32; + + /** Constant representing the Unicode KANNADA range. */ public static final int KANNADA = 1024; + + /** Constant representing the Unicode KHMER range. */ public static final int KHMER = 131072; + + /** Constant representing the Unicode LAO range. */ public static final int LAO = 8192; + + /** Constant representing the Unicode MALAYALAM range. */ public static final int MALAYALAM = 2048; + + /** Constant representing the Unicode MONGOLIAN range. */ public static final int MONGOLIAN = 262144; + + /** Constant representing the Unicode MYANMAR range. */ public static final int MYANMAR = 32768; + + /** Constant representing the Unicode ORIYA range. */ public static final int ORIYA = 128; + + /** + * Constant representing the Unicode TAMIL range. Note that + * there is no digit zero in this range; an ASCII digit zero + * is left unchanged when shaping to this range. + */ public static final int TAMIL = 256; + + /** Constant representing the Unicode TELUGU range. */ public static final int TELUGU = 512; + + /** Constant representing the Unicode THAI range. */ public static final int THAI = 4096; + + /** Constant representing the Unicode TIBETAN range. */ public static final int TIBETAN = 16384; - private int ranges; - private int context; - - private NumericShaper (int ranges, int context) + /** + * This table holds the zero digits for each language. This is hard-coded + * because the values will not change and the table layout is tied to the + * other constants in this class in any case. In the two places where a + * language does not have a zero digit, the character immediately preceeding + * the one digit is used instead. These languages are special-cased in + * the shaping code. + */ + private static final char[] zeroDigits = { - this.ranges = ranges; - this.context = context; + '0', // EUROPEAN + '\u0660', // ARABIC + '\u06f0', // EASTERN_ARABIC + '\u0966', // DEVANAGARI + '\u09e6', // BENGALI + '\u0a66', // GURMUKHI + '\u0ae6', // GUJARATI + '\u0b66', // ORIYA + '\u0be6', // TAMIL - special case as there is no digit zero + '\u0c66', // TELUGU + '\u0ce6', // KANNADA + '\u0d66', // MALAYALAM + '\u0e50', // THAI + '\u0ed0', // LAO + '\u0f20', // TIBETAN + '\u1040', // MYANMAR + '\u1368', // ETHIOPIC - special case as there is no digit zero + '\u17e0', // KHMER + '\u1810' // MONGOLIAN + }; + + /** + * The default initial context for this shaper, specified as + * an integer from 0 to 18. + */ + private int key; + + /** + * The target ranges handled by this shaper. If the shaper + * is not contextual, the high bit of this field will be set. + * @specnote This was discovered by reading the serialization spec + */ + private int mask; + + /** + * Create a new numeric shaper. The key given is a constant from + * this class, the constructor turns it into its internal form. + * @param key the key to use, as one of the manifest constants + * @param mask a mask of languages to shape for + */ + private NumericShaper (int key, int mask) + { + // This internal form is a bit goofy, but it is specified by + // the serialization spec. + this.key = Integer.numberOfTrailingZeros(key); + this.mask = mask; } - public boolean equals (Object obj) + /** + * Return an integer representing all the languages for which this + * shaper will shape. The result is taken by "or"ing together + * the constants representing the various languages. + */ + public int getRanges () { - if (! (obj instanceof NumericShaper)) - return false; + return mask & ALL_RANGES; + } - NumericShaper tmp = (NumericShaper) obj; - - return (ranges == tmp.ranges - && context == tmp.context); + /** + * Return true if this shaper is contextual, false if it is not. + */ + public boolean isContextual () + { + return mask > 0; } - public static NumericShaper getContextualShaper (int ranges) + /** + * Shape the text in the given array. The starting context will + * be the context passed to the shaper at creation time. + * @param text the text to shape + * @param start the index of the starting character of the array + * @param count the number of characters in the array + */ + public void shape (char[] text, int start, int count) { - throw new Error ("not implemented"); + shape (text, start, count, 1 << key); } - public static NumericShaper getContextualShaper (int ranges, - int defaultContext) + /** + * Given a unicode block object, return corresponding language constant. + * If the block is not recognized, returns zero. Note that as there + * is no separate ARABIC block in Character, this case must + * be specially handled by the caller; EASTERN_ARABIC is preferred when + * both are specified. + * @param b the unicode block to classify + * @return the language constant, or zero if not recognized + */ + private int classify(UnicodeBlock b) { - throw new Error ("not implemented"); + if (b == null) + return 0; + // ARABIC is handled by the caller; from testing we know + // that EASTERN_ARABIC takes precedence. + if (b == UnicodeBlock.ARABIC) + return EASTERN_ARABIC; + if (b == UnicodeBlock.BENGALI) + return BENGALI; + if (b == UnicodeBlock.DEVANAGARI) + return DEVANAGARI; + if (b == UnicodeBlock.ETHIOPIC) + return ETHIOPIC; + if (b == UnicodeBlock.BASIC_LATIN + || b == UnicodeBlock.LATIN_1_SUPPLEMENT + || b == UnicodeBlock.LATIN_EXTENDED_A + || b == UnicodeBlock.LATIN_EXTENDED_ADDITIONAL + || b == UnicodeBlock.LATIN_EXTENDED_B) + return EUROPEAN; + if (b == UnicodeBlock.GUJARATI) + return GUJARATI; + if (b == UnicodeBlock.GURMUKHI) + return GURMUKHI; + if (b == UnicodeBlock.KANNADA) + return KANNADA; + if (b == UnicodeBlock.KHMER) + return KHMER; + if (b == UnicodeBlock.LAO) + return LAO; + if (b == UnicodeBlock.MALAYALAM) + return MALAYALAM; + if (b == UnicodeBlock.MONGOLIAN) + return MONGOLIAN; + if (b == UnicodeBlock.MYANMAR) + return MYANMAR; + if (b == UnicodeBlock.ORIYA) + return ORIYA; + if (b == UnicodeBlock.TAMIL) + return TAMIL; + if (b == UnicodeBlock.TELUGU) + return TELUGU; + if (b == UnicodeBlock.THAI) + return THAI; + if (b == UnicodeBlock.TIBETAN) + return TIBETAN; + return 0; } - public int getRanges () + /** + * Shape the given text, using the indicated initial context. + * If this shaper is not a contextual shaper, then the given context + * will be ignored. + * @param text the text to shape + * @param start the index of the first character of the text to shape + * @param count the number of characters to shape in the text + * @param context the initial context + * @throws IllegalArgumentException if the initial context is invalid + */ + public void shape (char[] text, int start, int count, int context) { - return ranges; + int currentContext; + if (isContextual()) + { + if (Integer.bitCount(context) != 1 || (context & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("invalid context argument"); + // If the indicated context is not one we are handling, reset it. + if ((context & mask) == 0) + currentContext = -1; + else + currentContext = Integer.numberOfTrailingZeros(context); + } + else + currentContext = key; + + for (int i = 0; i < count; ++i) + { + char c = text[start + i]; + if (c >= '0' && c <= '9') + { + if (currentContext >= 0) + { + // Shape into the current context. + if (c == '0' + && ((1 << currentContext) == TAMIL + || (1 << currentContext) == ETHIOPIC)) + { + // No digit 0 in this context; do nothing. + } + else + text[start + i] + = (char) (zeroDigits[currentContext] + c - '0'); + } + } + else if (isContextual()) + { + // if c is in a group, set currentContext; else reset it. + int group = classify(UnicodeBlock.of(c)); + // Specially handle ARABIC. + if (group == EASTERN_ARABIC && (mask & EASTERN_ARABIC) == 0 + && (mask & ARABIC) != 0) + group = ARABIC; + if ((mask & group) != 0) + { + // The character was classified as being in a group + // we recognize, and it was selected by the shaper. + // So, change the context. + currentContext = Integer.numberOfTrailingZeros(group); + } + } + } } - public static NumericShaper getShaper (int singleRange) + public boolean equals (Object obj) { - throw new Error ("not implemented"); + if (! (obj instanceof NumericShaper)) + return false; + NumericShaper tmp = (NumericShaper) obj; + return key == tmp.key && mask == tmp.mask; } public int hashCode () { - throw new Error ("not implemented"); + return key ^ mask; } - public boolean isContextual () + public String toString () { - throw new Error ("not implemented"); + // For debugging only. + return "key=" + key + "; mask=" + mask; } - public void shape (char[] text, int start, int count) + /** + * Return a non-contextual shaper which can shape to a single range. + * All ASCII digits in the input text are translated to this language. + * @param singleRange the target language + * @return a non-contextual shaper for this language + * @throws IllegalArgumentException if the argument does not name a + * single language, as specified by the constants declared in this class + */ + public static NumericShaper getShaper (int singleRange) { - shape (text, start, count, context); + if (Integer.bitCount(singleRange) != 1) + throw new IllegalArgumentException("more than one bit set in argument"); + if ((singleRange & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("argument out of range"); + return new NumericShaper(singleRange, Integer.MIN_VALUE | singleRange); } - public void shape (char[] text, int start, int count, int context) + /** + * Return a contextual shaper which can shape to any of the indicated + * languages. The default initial context for this shaper is EUROPEAN. + * @param ranges the ranges to shape to + * @return a contextual shaper which will target any of these ranges + * @throws IllegalArgumentException if the argument specifies an + * unrecognized range + */ + public static NumericShaper getContextualShaper (int ranges) { - throw new Error ("not implemented"); + if ((ranges & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("argument out of range"); + return new NumericShaper(EUROPEAN, ranges); } - public String toString () + /** + * Return a contextual shaper which can shape to any of the indicated + * languages. The default initial context for this shaper is given as + * an argument. + * @param ranges the ranges to shape to + * @param defaultContext the default initial context + * @return a contextual shaper which will target any of these ranges + * @throws IllegalArgumentException if the ranges argument specifies an + * unrecognized range, or if the defaultContext argument does not specify + * a single valid range + */ + public static NumericShaper getContextualShaper (int ranges, + int defaultContext) { - throw new Error ("not implemented"); + if (Integer.bitCount(defaultContext) != 1) + throw new IllegalArgumentException("more than one bit set in context"); + if ((ranges & ~ALL_RANGES) != 0 || (defaultContext & ~ALL_RANGES) != 0) + throw new IllegalArgumentException("argument out of range"); + return new NumericShaper(defaultContext, ranges); } } diff --git a/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java index 6d64dec..d532085 100644 --- a/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java +++ b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.Rectangle2D; @@ -58,6 +60,7 @@ public final class ShapeGraphicAttribute extends GraphicAttribute } public void draw (Graphics2D graphics, float x, float y) + throws NotImplementedException { throw new Error ("not implemented"); } @@ -78,11 +81,13 @@ public final class ShapeGraphicAttribute extends GraphicAttribute } public float getAdvance () + throws NotImplementedException { throw new Error ("not implemented"); } public float getAscent () + throws NotImplementedException { throw new Error ("not implemented"); } @@ -93,6 +98,7 @@ public final class ShapeGraphicAttribute extends GraphicAttribute } public float getDescent () + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/font/TextMeasurer.java b/libjava/classpath/java/awt/font/TextMeasurer.java index 7fcdc87..18c286c 100644 --- a/libjava/classpath/java/awt/font/TextMeasurer.java +++ b/libjava/classpath/java/awt/font/TextMeasurer.java @@ -38,6 +38,8 @@ exception statement from your version. */ package java.awt.font; +import gnu.classpath.NotImplementedException; + import java.text.AttributedCharacterIterator; /** @@ -70,27 +72,32 @@ public final class TextMeasurer implements Cloneable public void deleteChar (AttributedCharacterIterator newParagraph, int deletePos) + throws NotImplementedException { throw new Error ("not implemented"); } public float getAdvanceBetween (int start, int limit) + throws NotImplementedException { throw new Error ("not implemented"); } public TextLayout getLayout (int start, int limit) + throws NotImplementedException { throw new Error ("not implemented"); } public int getLineBreakIndex (int start, float maxAdvance) + throws NotImplementedException { throw new Error ("not implemented"); } public void insertChar (AttributedCharacterIterator newParagraph, int insertPos) + throws NotImplementedException { throw new Error ("not implemented"); } diff --git a/libjava/classpath/java/awt/geom/GeneralPath.java b/libjava/classpath/java/awt/geom/GeneralPath.java index 15fb8ab..123833b 100644 --- a/libjava/classpath/java/awt/geom/GeneralPath.java +++ b/libjava/classpath/java/awt/geom/GeneralPath.java @@ -1,5 +1,5 @@ /* GeneralPath.java -- represents a shape built from subpaths - Copyright (C) 2002, 2003, 2004 Free Software Foundation + Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation This file is part of GNU Classpath. @@ -79,8 +79,16 @@ import java.awt.Shape; */ public final class GeneralPath implements Shape, Cloneable { - public static final int WIND_EVEN_ODD = PathIterator.WIND_EVEN_ODD; - public static final int WIND_NON_ZERO = PathIterator.WIND_NON_ZERO; + // WORKAROUND for gcj 4.0.x (x < 3) + // fully qualify PathIterator constants. + + /** Same constant as {@link PathIterator#WIND_EVEN_ODD}. */ + public static final int WIND_EVEN_ODD + = java.awt.geom.PathIterator.WIND_EVEN_ODD; + + /** Same constant as {@link PathIterator.WIND_NON_ZERO}. */ + public static final int WIND_NON_ZERO + = java.awt.geom.PathIterator.WIND_NON_ZERO; /** Initial size if not specified. */ private static final int INIT_SIZE = 10; diff --git a/libjava/classpath/java/awt/geom/Point2D.java b/libjava/classpath/java/awt/geom/Point2D.java index 9f22a5a..a2689ab 100644 --- a/libjava/classpath/java/awt/geom/Point2D.java +++ b/libjava/classpath/java/awt/geom/Point2D.java @@ -1,5 +1,5 @@ /* Point2D.java -- generic point in 2-D space - Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation + Copyright (C) 1999, 2000, 2002, 2004, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -135,7 +135,7 @@ public abstract class Point2D implements Cloneable */ public double distanceSq(double x, double y) { - return distanceSq(getX(), x, getY(), y); + return distanceSq(getX(), getY(), x, y); } /** @@ -147,7 +147,7 @@ public abstract class Point2D implements Cloneable */ public double distanceSq(Point2D p) { - return distanceSq(getX(), p.getX(), getY(), p.getY()); + return distanceSq(getX(), getY(), p.getX(), p.getY()); } /** @@ -159,7 +159,7 @@ public abstract class Point2D implements Cloneable */ public double distance(double x, double y) { - return distance(getX(), x, getY(), y); + return distance(getX(), getY(), x, y); } /** @@ -171,7 +171,7 @@ public abstract class Point2D implements Cloneable */ public double distance(Point2D p) { - return distance(getX(), p.getX(), getY(), p.getY()); + return distance(getX(), getY(), p.getX(), p.getY()); } /** diff --git a/libjava/classpath/java/awt/image/AffineTransformOp.java b/libjava/classpath/java/awt/image/AffineTransformOp.java index f11066e..bb4b795 100644 --- a/libjava/classpath/java/awt/image/AffineTransformOp.java +++ b/libjava/classpath/java/awt/image/AffineTransformOp.java @@ -347,7 +347,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp * @param dstPt destination point * @return the location of the transformed source point. */ - public Point2D getPoint2D (Point2D srcPt, Point2D dstPt) + public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { return transform.transform (srcPt, dstPt); } diff --git a/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java b/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java index 6333ce9..44d5cec 100644 --- a/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java +++ b/libjava/classpath/java/awt/image/AreaAveragingScaleFilter.java @@ -1,5 +1,5 @@ /* AreaAveragingScaleFilter.java -- Java class for filtering images - Copyright (C) 1999 Free Software Foundation, Inc. + Copyright (C) 1999,2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,86 +45,225 @@ package java.awt.image; * points should give the desired results although Sun does not * specify what the exact algorithm should be. * <br> - * FIXME: Currently this filter does nothing and needs to be implemented. * * @author C. Brian Jones (cbj@gnu.org) */ public class AreaAveragingScaleFilter extends ReplicateScaleFilter { - /** - * Construct an instance of <code>AreaAveragingScaleFilter</code> which - * should be used in conjunction with a <code>FilteredImageSource</code> - * object. - * - * @param width the width of the destination image - * @param height the height of the destination image - */ - public AreaAveragingScaleFilter(int width, int height) { - super(width, height); - } - - /** - * The <code>ImageProducer</code> should call this method with a - * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, - * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, - * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the - * <code>ImageConsumer</code> interface. - * <br> - * FIXME - more than likely Sun's implementation desires - * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here - * in order to assure that mask is part of the hints added to - * the consumer. - * - * @param flags a bit mask of hints - * @see ImageConsumer - */ - public void setHints(int flags) - { - if (consumer != null) - consumer.setHints(flags); - } - - /** - * This function delivers a rectangle of pixels where any - * pixel(m,n) is stored in the array as a <code>byte</code> at - * index (n * scansize + m + offset). - * - * @param x the x coordinate of the rectangle - * @param y the y coordinate of the rectangle - * @param w the width of the rectangle - * @param h the height of the rectangle - * @param model the <code>ColorModel</code> used to translate the pixels - * @param pixels the array of pixel values - * @param offset the index of the first pixels in the <code>pixels</code> array - * @param scansize the width to use in extracting pixels from the <code>pixels</code> array - */ - public void setPixels(int x, int y, int w, int h, - ColorModel model, byte[] pixels, int offset, int scansize) - { - if (consumer != null) - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); - } - - /** - * This function delivers a rectangle of pixels where any - * pixel(m,n) is stored in the array as an <code>int</code> at - * index (n * scansize + m + offset). - * - * @param x the x coordinate of the rectangle - * @param y the y coordinate of the rectangle - * @param w the width of the rectangle - * @param h the height of the rectangle - * @param model the <code>ColorModel</code> used to translate the pixels - * @param pixels the array of pixel values - * @param offset the index of the first pixels in the <code>pixels</code> array - * @param scansize the width to use in extracting pixels from the <code>pixels</code> array - */ - public void setPixels(int x, int y, int w, int h, - ColorModel model, int[] pixels, int offset, int scansize) - { - if (consumer != null) - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); - } + /** + * Construct an instance of <code>AreaAveragingScaleFilter</code> which + * should be used in conjunction with a <code>FilteredImageSource</code> + * object. + * + * @param width the width of the destination image + * @param height the height of the destination image + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + /** + * The <code>ImageProducer</code> should call this method with a + * bit mask of hints from any of <code>RANDOMPIXELORDER</code>, + * <code>TOPDOWNLEFTRIGHT</code>, <code>COMPLETESCANLINES</code>, + * <code>SINGLEPASS</code>, <code>SINGLEFRAME</code> from the + * <code>ImageConsumer</code> interface. + * <br> + * FIXME - more than likely Sun's implementation desires + * <code>TOPDOWNLEFTRIGHT</code> order and this method is overloaded here + * in order to assure that mask is part of the hints added to + * the consumer. + * + * @param flags a bit mask of hints + * @see ImageConsumer + */ + public void setHints(int flags) + { + if (consumer != null) + consumer.setHints(flags); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as a <code>byte</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + byte[] destPixels = averagePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + if (consumer != null) + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This function delivers a rectangle of pixels where any + * pixel(m,n) is stored in the array as an <code>int</code> at + * index (n * scansize + m + offset). + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param model the <code>ColorModel</code> used to translate the pixels + * @param pixels the array of pixel values + * @param offset the index of the first pixels in the <code>pixels</code> array + * @param scansize the width to use in extracting pixels from the <code>pixels</code> array + */ + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, int offset, int scansize) + { + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + int[] destPixels = averagePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + if (consumer != null) + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); + } + + /** + * This is a really terrible implementation, + * since it uses the nearest-neighbor method. This filter is rarely used though. + * + * @param srcx, srcy - Source rectangle upper-left corner + * @param srcw, srch - Source rectangle width and height + * @param model - Pixel color model + * @param srcPixels - Source pixel data. + * @param srcOffset - Starting offset into the source pixel data array. + * @param srcScansize - Source array scanline size. + * @param rx,ry - Scaling factor. + * @param dstScansize - Destination array scanline size. + */ + private byte[] averagePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, byte[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int destW = (int) Math.ceil(srcw/rx); + int destH = (int) Math.ceil(srch/ry); + byte[] destPixels = new byte[ destW * destH ]; + int sx, sy; + + int w = (int)Math.ceil(rx); + int h = (int)Math.ceil(ry); + + for(int x = 0; x < destW; x++) + for(int y = 0; y < destH; y++) + { + sx = (int) (x * rx); + sy = (int) (y * ry); + + int r,g,b,a; + r = g = b = a = 0; + + for(int i = 0; i < w; i++) + { + for(int j = 0; j < h; j++) + { + int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; + r += model.getRed(srcPixels[ idx ]); + g += model.getGreen(srcPixels[ idx ]); + b += model.getBlue(srcPixels[ idx ]); + a += model.getAlpha(srcPixels[ idx ]); + } + } + + r = r / (w * h); + g = g / (w * h); + b = b / (w * h); + a = a / (w * h); + + // Does this really work? + destPixels[x + destScansize*y] = (byte)model.getDataElement + (new int[]{r, g, b, a}, 0); + } + + return destPixels; + } + + /** + * This is a really terrible implementation, + * since it uses the nearest-neighbor method. This filter is rarely used though. + * + * @param srcx, srcy - Source rectangle upper-left corner + * @param srcw, srch - Source rectangle width and height + * @param model - Pixel color model + * @param srcPixels - Source pixel data. + * @param srcOffset - Starting offset into the source pixel data array. + * @param srcScansize - Source array scanline size. + * @param rx,ry - Scaling factor. + * @param dstScansize - Destination array scanline size. + */ + private int[] averagePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, int[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int destW = (int) Math.ceil(srcw/rx); + int destH = (int) Math.ceil(srch/ry); + int[] destPixels = new int[ destW * destH ]; + int sx, sy; + + int w = (int)Math.ceil(rx); + int h = (int)Math.ceil(ry); + + for(int x = 0; x < destW; x++) + for(int y = 0; y < destH; y++) + { + sx = (int) (x * rx); + sy = (int) (y * ry); + + int r,g,b,a; + r = g = b = a = 0; + + for(int i = 0; i < w; i++) + { + for(int j = 0; j < h; j++) + { + int idx = srcx + sx + i + (srcy + sy + j)*srcScansize; + r += model.getRed(srcPixels[ idx ]); + g += model.getGreen(srcPixels[ idx ]); + b += model.getBlue(srcPixels[ idx ]); + a += model.getAlpha(srcPixels[ idx ]); + } + } + + r = r / (w * h); + g = g / (w * h); + b = b / (w * h); + a = a / (w * h); + + destPixels[x + destScansize*y] = model.getDataElement + (new int[]{r, g, b, a}, 0); + } + + return destPixels; + } } diff --git a/libjava/classpath/java/awt/image/BandCombineOp.java b/libjava/classpath/java/awt/image/BandCombineOp.java index 79efb02..634125e 100644 --- a/libjava/classpath/java/awt/image/BandCombineOp.java +++ b/libjava/classpath/java/awt/image/BandCombineOp.java @@ -118,7 +118,7 @@ public class BandCombineOp implements RasterOp /* (non-Javadoc) * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) */ - public Rectangle2D getBounds2D(Raster src) + public final Rectangle2D getBounds2D(Raster src) { return src.getBounds(); } @@ -144,7 +144,7 @@ public class BandCombineOp implements RasterOp * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, *java.awt.geom.Point2D) */ - public Point2D getPoint2D(Point2D src, Point2D dst) + public final Point2D getPoint2D(Point2D src, Point2D dst) { if (dst == null) return (Point2D)src.clone(); dst.setLocation(src); @@ -154,13 +154,13 @@ public class BandCombineOp implements RasterOp /* (non-Javadoc) * @see java.awt.image.RasterOp#getRenderingHints() */ - public RenderingHints getRenderingHints() + public final RenderingHints getRenderingHints() { return hints; } /** Return the matrix for this Op. */ - public float[][] getMatrix() + public final float[][] getMatrix() { return matrix; } diff --git a/libjava/classpath/java/awt/image/ColorModel.java b/libjava/classpath/java/awt/image/ColorModel.java index 1ced2a0..40307f2 100644 --- a/libjava/classpath/java/awt/image/ColorModel.java +++ b/libjava/classpath/java/awt/image/ColorModel.java @@ -452,8 +452,14 @@ public abstract class ColorModel implements Transparency * This method is typically overriden in subclasses to provide a * more efficient implementation. * - * @param array of transferType containing a single pixel. The - * pixel should be encoded in the natural way of the color model. + * @param pixel an array of transferType containing a single pixel. The + * pixel should be encoded in the natural way of the color model. If + * this argument is not an array, as expected, a {@link ClassCastException} + * will be thrown. + * @param components an array that will be filled with the color component + * of the pixel. If this is null, a new array will be allocated + * @param offset index into the components array at which the result + * will be stored * * @return arrays of unnormalized component samples of single * pixel. The scale and multiplication state of the samples are @@ -521,8 +527,8 @@ public abstract class ColorModel implements Transparency float[] normComponents, int normOffset) { - // subclasses has to implement this method. - throw new UnsupportedOperationException(); + int[] components = getComponents(pixel, null, 0); + return getNormalizedComponents(components, 0, normComponents, normOffset); } /** diff --git a/libjava/classpath/java/awt/image/ComponentSampleModel.java b/libjava/classpath/java/awt/image/ComponentSampleModel.java index 5cf06e4..b4e9450 100644 --- a/libjava/classpath/java/awt/image/ComponentSampleModel.java +++ b/libjava/classpath/java/awt/image/ComponentSampleModel.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2002 Free Software Foundation +/* Copyright (C) 2000, 2002, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -38,6 +38,8 @@ package java.awt.image; import gnu.java.awt.Buffers; +import java.util.Arrays; + /* FIXME: This class does not yet support data type TYPE_SHORT */ /** @@ -60,11 +62,14 @@ import gnu.java.awt.Buffers; */ public class ComponentSampleModel extends SampleModel { + /** The offsets to the first sample for each band. */ protected int[] bandOffsets; + + /** The indices of the bank used to store each band in a data buffer. */ protected int[] bankIndices; /** - * Number of bands in the image described. + * The number of bands in the image. * @specnote This field shadows the protected numBands in SampleModel. */ protected int numBands; @@ -72,42 +77,128 @@ public class ComponentSampleModel extends SampleModel /** Used when creating data buffers. */ protected int numBanks; + /** + * The number of data elements between a sample in one row and the + * corresponding sample in the next row. + */ protected int scanlineStride; + /** + * The number of data elements between a sample for one pixel and the + * corresponding sample for the next pixel in the same row. + */ protected int pixelStride; private boolean tightPixelPacking = false; + /** + * Creates a new sample model that assumes that all bands are stored in a + * single bank of the {@link DataBuffer}. + * <p> + * Note that the <code>bandOffsets</code> array is copied to internal storage + * to prevent subsequent changes to the array from affecting this object. + * + * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, + * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or + * {@link DataBuffer#TYPE_DOUBLE}). + * @param w the width in pixels. + * @param h the height in pixels. + * @param pixelStride the number of data elements in the step from a sample + * in one pixel to the corresponding sample in the next pixel. + * @param scanlineStride the number of data elements in the step from a + * sample in a pixel to the corresponding sample in the pixel in the next + * row. + * @param bandOffsets the offset to the first element for each band, with + * the size of the array defining the number of bands (<code>null</code> + * not permitted). + * + * @throws IllegalArgumentException if <code>dataType</code> is not one of + * the specified values. + * @throws IllegalArgumentException if <code>w</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>h</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>w * h</code> exceeds + * {@link Integer#MAX_VALUE}. + * @throws IllegalArgumentException if <code>pixelStride</code> is negative. + * @throws IllegalArgumentException if <code>scanlineStride</code> is less + * than or equal to zero. + * @throws IllegalArgumentException if <code>bandOffsets</code> has zero + * length. + */ public ComponentSampleModel(int dataType, - int w, int h, - int pixelStride, - int scanlineStride, - int[] bandOffsets) + int w, int h, + int pixelStride, + int scanlineStride, + int[] bandOffsets) { this(dataType, w, h, pixelStride, scanlineStride, - new int[bandOffsets.length], bandOffsets); + new int[bandOffsets.length], bandOffsets); } + /** + * Creates a new sample model that assumes that all bands are stored in a + * single bank of the {@link DataBuffer}. + * + * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, + * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or + * {@link DataBuffer#TYPE_DOUBLE}). + * @param w the width in pixels. + * @param h the height in pixels. + * @param pixelStride the number of data elements in the step from a sample + * in one pixel to the corresponding sample in the next pixel. + * @param scanlineStride the number of data elements in the step from a + * sample in a pixel to the corresponding sample in the pixel in the next + * row. + * @param bankIndices the index of the bank in which each band is stored + * (<code>null</code> not permitted). This array is copied to internal + * storage so that subsequent updates to the array do not affect the sample + * model. + * @param bandOffsets the offset to the first element for each band, with + * the size of the array defining the number of bands (<code>null</code> + * not permitted). This array is copied to internal storage so that + * subsequent updates to the array do not affect the sample model. + * + * @throws IllegalArgumentException if <code>dataType</code> is not one of + * the specified values. + * @throws IllegalArgumentException if <code>w</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>h</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>w * h</code> exceeds + * {@link Integer#MAX_VALUE}. + * @throws IllegalArgumentException if <code>pixelStride</code> is negative. + * @throws IllegalArgumentException if <code>scanlineStride</code> is less + * than or equal to zero. + * @throws IllegalArgumentException if <code>bandOffsets</code> has zero + * length. + */ public ComponentSampleModel(int dataType, - int w, int h, - int pixelStride, - int scanlineStride, - int[] bankIndices, - int[] bandOffsets) + int w, int h, + int pixelStride, + int scanlineStride, + int[] bankIndices, + int[] bandOffsets) { super(dataType, w, h, bandOffsets.length); - if ((pixelStride<0) || (scanlineStride<0) || - (bandOffsets.length<1) || - (bandOffsets.length != bankIndices.length)) + + // super permits DataBuffer.TYPE_UNDEFINED but this class doesn't... + if (dataType == DataBuffer.TYPE_UNDEFINED) + throw new IllegalArgumentException("Unsupported dataType."); + + if ((pixelStride < 0) || (scanlineStride < 0) || (bandOffsets.length < 1) + || (bandOffsets.length != bankIndices.length)) throw new IllegalArgumentException(); - this.bandOffsets = bandOffsets; - this.bankIndices = bankIndices; + this.bandOffsets = (int[]) bandOffsets.clone(); + this.bankIndices = (int[]) bankIndices.clone(); this.numBands = bandOffsets.length; this.numBanks = 0; - for (int b=0; b<bankIndices.length; b++) - this.numBanks = Math.max(this.numBanks, bankIndices[b]+1); + for (int b = 0; b < bankIndices.length; b++) + this.numBanks = Math.max(this.numBanks, bankIndices[b] + 1); this.scanlineStride = scanlineStride; this.pixelStride = pixelStride; @@ -116,68 +207,122 @@ public class ComponentSampleModel extends SampleModel /* FIXME: May these checks should be reserved for the PixelInterleavedSampleModel? */ - + if (pixelStride == numBands) { - tightPixelPacking = true; - for (int b=0; b<numBands; b++) { - if ((bandOffsets[b] != b) || (bankIndices[b] !=0)) - { - tightPixelPacking = false; - break; - } - } + tightPixelPacking = true; + for (int b = 0; b < numBands; b++) { + if ((bandOffsets[b] != b) || (bankIndices[b] != 0)) + { + tightPixelPacking = false; + break; + } + } } - } - + } + + /** + * Creates a new sample model that is compatible with this one, but with the + * specified dimensions. + * + * @param w the width (must be greater than zero). + * @param h the height (must be greater than zero). + * + * @return A new sample model. + */ public SampleModel createCompatibleSampleModel(int w, int h) { return new ComponentSampleModel(dataType, w, h, pixelStride, - scanlineStride, bankIndices, - bandOffsets); + scanlineStride, bankIndices, + bandOffsets); } + /** + * Creates a new sample model that provides access to a subset of the bands + * that this sample model supports. + * + * @param bands the bands (<code>null</code> not permitted). + * + * @return The new sample model. + */ public SampleModel createSubsetSampleModel(int[] bands) { int numBands = bands.length; int[] bankIndices = new int[numBands]; int[] bandOffsets = new int[numBands]; - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) { - bankIndices[b] = this.bankIndices[bands[b]]; - bandOffsets[b] = this.bandOffsets[bands[b]]; + bankIndices[b] = this.bankIndices[bands[b]]; + bandOffsets[b] = this.bandOffsets[bands[b]]; } return new ComponentSampleModel(dataType, width, height, pixelStride, - scanlineStride, bankIndices, - bandOffsets); + scanlineStride, bankIndices, + bandOffsets); } + /** + * Creates a new data buffer that is compatible with this sample model. + * + * @return The new data buffer. + */ public DataBuffer createDataBuffer() { // Maybe this value should be precalculated in the constructor? int highestOffset = 0; - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) { - highestOffset = Math.max(highestOffset, bandOffsets[b]); + highestOffset = Math.max(highestOffset, bandOffsets[b]); } - int size = pixelStride*(width-1) + scanlineStride*(height-1) + - highestOffset + 1; + int size = pixelStride * (width - 1) + scanlineStride * (height - 1) + + highestOffset + 1; return Buffers.createBuffer(getDataType(), size, numBanks); } + /** + * Returns the offset of the sample in band 0 for the pixel at location + * <code>(x, y)</code>. This offset can be used to read a sample value from + * a {@link DataBuffer}. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * + * @return The offset. + * + * @see #getOffset(int, int, int) + */ public int getOffset(int x, int y) { return getOffset(x, y, 0); } + /** + * Returns the offset of the sample in band <code>b</code> for the pixel at + * location <code>(x, y)</code>. This offset can be used to read a sample + * value from a {@link DataBuffer}. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * + * @return The offset. + */ public int getOffset(int x, int y, int b) { - return bandOffsets[b] + pixelStride*x + scanlineStride*y; + return bandOffsets[b] + pixelStride * x + scanlineStride * y; } + /** + * Returns the size in bits for each sample (one per band). For this sample + * model, each band has the same sample size and this is determined by the + * data type for the sample model. + * + * @return The sample sizes. + * + * @see SampleModel#getDataType() + */ public final int[] getSampleSize() { int size = DataBuffer.getDataTypeSize(getDataType()); @@ -187,39 +332,101 @@ public class ComponentSampleModel extends SampleModel return sizes; } + /** + * Returns the size in bits for the samples in the specified band. In this + * class, the sample size is the same for every band and is determined from + * the data type for the model. + * + * @param band the band index (ignored here). + * + * @return The sample size in bits. + * + * @see SampleModel#getDataType() + */ public final int getSampleSize(int band) { return DataBuffer.getDataTypeSize(getDataType()); } + /** + * Returns the indices of the bank(s) in the {@link DataBuffer} used to + * store the samples for each band. The returned array is a copy, so that + * altering it will not impact the sample model. + * + * @return The bank indices. + */ public final int[] getBankIndices() { - return bankIndices; + return (int[]) bankIndices.clone(); } + /** + * Returns the offsets to the first sample in each band. The returned array + * is a copy, so that altering it will not impact the sample model. + * + * @return The offsets. + */ public final int[] getBandOffsets() { - return bandOffsets; + return (int[]) bandOffsets.clone(); } + /** + * Returns the distance (in terms of element indices) between the sample for + * one pixel and the corresponding sample for the equivalent pixel in the + * next row. This is used in the calculation of the element offset for + * retrieving samples from a {@link DataBuffer}. + * + * @return The distance between pixel samples in consecutive rows. + */ public final int getScanlineStride() { return scanlineStride; } + /** + * Returns the distance (in terms of element indices) between the sample for + * one pixel and the corresponding sample for the next pixel in a row. This + * is used in the calculation of the element offset for retrieving samples + * from a {@link DataBuffer}. + * + * @return The distance between pixel samples in the same row. + */ public final int getPixelStride() { return pixelStride; } + /** + * Returns the number of data elements used to store the samples for one + * pixel. In this model, this is the same as the number of bands. + * + * @return The number of data elements used to store the samples for one + * pixel. + */ public final int getNumDataElements() { return numBands; } + /** + * Returns the samples for the pixel at location <code>(x, y)</code> in + * a primitive array (the array type is determined by the data type for + * this model). The <code>obj</code> argument provides an option to supply + * an existing array to hold the result, if this is <code>null</code> a new + * array will be allocated. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param obj a primitive array that, if not <code>null</code>, will be + * used to store and return the sample values. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return An array of sample values for the specified pixel. + */ public Object getDataElements(int x, int y, Object obj, DataBuffer data) { - int xyOffset = pixelStride*x + scanlineStride*y; + int xyOffset = pixelStride * x + scanlineStride * y; int[] totalBandDataOffsets = new int[numBands]; @@ -235,124 +442,147 @@ public class ComponentSampleModel extends SampleModel int[] bankOffsets = data.getOffsets(); - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) { - totalBandDataOffsets[b] = - bandOffsets[b]+bankOffsets[bankIndices[b]] + xyOffset; + totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]] + + xyOffset; } - + try { - switch (getTransferType()) - { - case DataBuffer.TYPE_BYTE: - DataBufferByte inByte = (DataBufferByte) data; - byte[] outByte = (byte[]) obj; - if (outByte == null) outByte = new byte[numBands]; - - for (int b=0; b<numBands; b++) - { - int dOffset = totalBandDataOffsets[b]; - outByte[b] = inByte.getData(bankIndices[b])[dOffset]; - } - return outByte; - - case DataBuffer.TYPE_USHORT: - DataBufferUShort inUShort = (DataBufferUShort) data; - short[] outUShort = (short[]) obj; - if (outUShort == null) outUShort = new short[numBands]; - - for (int b=0; b<numBands; b++) - { - int dOffset = totalBandDataOffsets[b]; - outUShort[b] = inUShort.getData(bankIndices[b])[dOffset]; - } - return outUShort; - - case DataBuffer.TYPE_SHORT: - DataBufferShort inShort = (DataBufferShort) data; - short[] outShort = (short[]) obj; - if (outShort == null) outShort = new short[numBands]; - - for (int b=0; b<numBands; b++) - { - int dOffset = totalBandDataOffsets[b]; - outShort[b] = inShort.getData(bankIndices[b])[dOffset]; - } - return outShort; - - case DataBuffer.TYPE_INT: - DataBufferInt inInt = (DataBufferInt) data; - int[] outInt = (int[]) obj; - if (outInt == null) outInt = new int[numBands]; - - for (int b=0; b<numBands; b++) - { - int dOffset = totalBandDataOffsets[b]; - outInt[b] = inInt.getData(bankIndices[b])[dOffset]; - } - return outInt; - - case DataBuffer.TYPE_FLOAT: - DataBufferFloat inFloat = (DataBufferFloat) data; - float[] outFloat = (float[]) obj; - if (outFloat == null) outFloat = new float[numBands]; - - for (int b=0; b<numBands; b++) - { - int dOffset = totalBandDataOffsets[b]; - outFloat[b] = inFloat.getData(bankIndices[b])[dOffset]; - } - return outFloat; - - case DataBuffer.TYPE_DOUBLE: - DataBufferDouble inDouble = (DataBufferDouble) data; - double[] outDouble = (double[]) obj; - if (outDouble == null) outDouble = new double[numBands]; - - for (int b=0; b<numBands; b++) - { - int dOffset = totalBandDataOffsets[b]; - outDouble[b] = inDouble.getData(bankIndices[b])[dOffset]; - } - return outDouble; - - default: - throw new IllegalStateException("unknown transfer type " + - getTransferType()); - } + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + DataBufferByte inByte = (DataBufferByte) data; + byte[] outByte = (byte[]) obj; + if (outByte == null) + outByte = new byte[numBands]; + + for (int b = 0; b < numBands; b++) + { + int dOffset = totalBandDataOffsets[b]; + outByte[b] = inByte.getData(bankIndices[b])[dOffset]; + } + return outByte; + + case DataBuffer.TYPE_USHORT: + DataBufferUShort inUShort = (DataBufferUShort) data; + short[] outUShort = (short[]) obj; + if (outUShort == null) + outUShort = new short[numBands]; + + for (int b = 0; b < numBands; b++) + { + int dOffset = totalBandDataOffsets[b]; + outUShort[b] = inUShort.getData(bankIndices[b])[dOffset]; + } + return outUShort; + + case DataBuffer.TYPE_SHORT: + DataBufferShort inShort = (DataBufferShort) data; + short[] outShort = (short[]) obj; + if (outShort == null) + outShort = new short[numBands]; + + for (int b = 0; b < numBands; b++) + { + int dOffset = totalBandDataOffsets[b]; + outShort[b] = inShort.getData(bankIndices[b])[dOffset]; + } + return outShort; + + case DataBuffer.TYPE_INT: + DataBufferInt inInt = (DataBufferInt) data; + int[] outInt = (int[]) obj; + if (outInt == null) + outInt = new int[numBands]; + + for (int b = 0; b < numBands; b++) + { + int dOffset = totalBandDataOffsets[b]; + outInt[b] = inInt.getData(bankIndices[b])[dOffset]; + } + return outInt; + + case DataBuffer.TYPE_FLOAT: + DataBufferFloat inFloat = (DataBufferFloat) data; + float[] outFloat = (float[]) obj; + if (outFloat == null) + outFloat = new float[numBands]; + + for (int b = 0; b < numBands; b++) + { + int dOffset = totalBandDataOffsets[b]; + outFloat[b] = inFloat.getData(bankIndices[b])[dOffset]; + } + return outFloat; + + case DataBuffer.TYPE_DOUBLE: + DataBufferDouble inDouble = (DataBufferDouble) data; + double[] outDouble = (double[]) obj; + if (outDouble == null) + outDouble = new double[numBands]; + + for (int b = 0; b < numBands; b++) + { + int dOffset = totalBandDataOffsets[b]; + outDouble[b] = inDouble.getData(bankIndices[b])[dOffset]; + } + return outDouble; + + default: + throw new IllegalStateException("unknown transfer type " + + getTransferType()); + } } catch (ArrayIndexOutOfBoundsException aioobe) { - String msg = "While reading data elements, " + - "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset + - ", data.getSize()=" + data.getSize() + ": " + aioobe; - throw new ArrayIndexOutOfBoundsException(msg); + String msg = "While reading data elements, " + + "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset + + ", data.getSize()=" + data.getSize() + ": " + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); } } + /** + * Returns the samples for the pixels in the region defined by + * <code>(x, y, w, h)</code> in a primitive array (the array type is + * determined by the data type for this model). The <code>obj</code> + * argument provides an option to supply an existing array to hold the + * result, if this is <code>null</code> a new array will be allocated. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + * @param obj a primitive array that, if not <code>null</code>, will be + * used to store and return the sample values. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return An array of sample values for the specified pixels. + * + * @see #setDataElements(int, int, int, int, Object, DataBuffer) + */ public Object getDataElements(int x, int y, int w, int h, Object obj, - DataBuffer data) + DataBuffer data) { if (!tightPixelPacking) { - return super.getDataElements(x, y, w, h, obj, data); + return super.getDataElements(x, y, w, h, obj, data); } // using get speedup // We can copy whole rows - int rowSize = w*numBands; - int dataSize = rowSize*h; + int rowSize = w * numBands; + int dataSize = rowSize * h; - DataBuffer transferBuffer = - Buffers.createBuffer(getTransferType(), obj, dataSize); + DataBuffer transferBuffer = Buffers.createBuffer(getTransferType(), obj, + dataSize); obj = Buffers.getData(transferBuffer); - int inOffset = - pixelStride*x + - scanlineStride*y + - data.getOffset(); // Assumes only one band is used + int inOffset = pixelStride * x + scanlineStride * y + data.getOffset(); + // Assumes only one band is used /* We don't add band offsets since we assume that bands have offsets 0, 1, 2, ... */ @@ -360,189 +590,345 @@ public class ComponentSampleModel extends SampleModel // See if we can copy everything in one go if (scanlineStride == rowSize) { - // Collapse scan lines: - rowSize *= h; - // We ignore scanlineStride since it won't be of any use - h = 1; + // Collapse scan lines: + rowSize *= h; + // We ignore scanlineStride since it won't be of any use + h = 1; } int outOffset = 0; Object inArray = Buffers.getData(data); - for (int yd = 0; yd<h; yd++) + for (int yd = 0; yd < h; yd++) { - System.arraycopy(inArray, inOffset, obj, outOffset, rowSize); - inOffset += scanlineStride; - outOffset += rowSize; + System.arraycopy(inArray, inOffset, obj, outOffset, rowSize); + inOffset += scanlineStride; + outOffset += rowSize; } return obj; } + /** + * Sets the samples for the pixels in the region defined by + * <code>(x, y, w, h)</code> from a supplied primitive array (the array type + * must be consistent with the data type for this model). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + * @param obj a primitive array containing the sample values. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getDataElements(int, int, int, int, Object, DataBuffer) + */ public void setDataElements(int x, int y, int w, int h, - Object obj, DataBuffer data) + Object obj, DataBuffer data) { if (!tightPixelPacking) { - super.setDataElements(x, y, w, h, obj, data); - return; + super.setDataElements(x, y, w, h, obj, data); + return; } // using set speedup, we can copy whole rows - int rowSize = w*numBands; - int dataSize = rowSize*h; + int rowSize = w * numBands; + int dataSize = rowSize * h; - DataBuffer transferBuffer = - Buffers.createBufferFromData(getTransferType(), obj, dataSize); + DataBuffer transferBuffer + = Buffers.createBufferFromData(getTransferType(), obj, dataSize); int[] bankOffsets = data.getOffsets(); - int outOffset = - pixelStride*x + - scanlineStride*y + - bankOffsets[0]; // same assuptions as in get... + int outOffset = pixelStride * x + scanlineStride * y + bankOffsets[0]; + // same assumptions as in get... // See if we can copy everything in one go if (scanlineStride == rowSize) { - // Collapse scan lines: - rowSize *= h; - h = 1; + // Collapse scan lines: + rowSize *= h; + h = 1; } int inOffset = 0; Object outArray = Buffers.getData(data); - for (int yd = 0; yd<h; yd++) + for (int yd = 0; yd < h; yd++) { - System.arraycopy(obj, inOffset, outArray, outOffset, rowSize); - outOffset += scanlineStride; - inOffset += rowSize; + System.arraycopy(obj, inOffset, outArray, outOffset, rowSize); + outOffset += scanlineStride; + inOffset += rowSize; } } + /** + * Returns all the samples for the pixel at location <code>(x, y)</code> + * stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param iArray an array that will be populated with the sample values and + * returned as the result. The size of this array should be equal to the + * number of bands in the model. If the array is <code>null</code>, a new + * array is created. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The samples for the specified pixel. + * + * @see #setPixel(int, int, int[], DataBuffer) + */ public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { - int offset = pixelStride*x + scanlineStride*y; - if (iArray == null) iArray = new int[numBands]; - for (int b=0; b<numBands; b++) + int offset = pixelStride * x + scanlineStride * y; + if (iArray == null) + iArray = new int[numBands]; + for (int b = 0; b < numBands; b++) { - iArray[b] = data.getElem(bankIndices[b], offset+bandOffsets[b]); + iArray[b] = data.getElem(bankIndices[b], offset + bandOffsets[b]); } return iArray; } + /** + * Returns the samples for all the pixels in a rectangular region. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param w the width. + * @param h the height. + * @param iArray an array that if non-<code>null</code> will be populated + * with the sample values and returned as the result. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The samples for all the pixels in the rectangle. + */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, - DataBuffer data) + DataBuffer data) { - int offset = pixelStride*x + scanlineStride*y; - if (iArray == null) iArray = new int[numBands*w*h]; + int offset = pixelStride * x + scanlineStride * y; + if (iArray == null) + iArray = new int[numBands * w * h]; int outOffset = 0; - for (y=0; y<h; y++) + for (y = 0; y < h; y++) { - int lineOffset = offset; - for (x=0; x<w; x++) - { - for (int b=0; b<numBands; b++) - { - iArray[outOffset++] = - data.getElem(bankIndices[b], lineOffset+bandOffsets[b]); - } - lineOffset += pixelStride; - } - offset += scanlineStride; + int lineOffset = offset; + for (x = 0; x < w; x++) + { + for (int b = 0; b < numBands; b++) + { + iArray[outOffset++] + = data.getElem(bankIndices[b], lineOffset+bandOffsets[b]); + } + lineOffset += pixelStride; + } + offset += scanlineStride; } return iArray; } - + + /** + * Returns the sample for band <code>b</code> of the pixel at + * <code>(x, y)</code> that is stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * @param data the data buffer (<code>null</code> not permitted). + * + * @return The sample value. + * + * @see #setSample(int, int, int, int, DataBuffer) + */ public int getSample(int x, int y, int b, DataBuffer data) { return data.getElem(bankIndices[b], getOffset(x, y, b)); } + /** + * Sets the samples for the pixel at location <code>(x, y)</code> from the + * supplied primitive array (the array type must be consistent with the data + * type for this model). + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param obj a primitive array containing the pixel's sample values. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #setDataElements(int, int, Object, DataBuffer) + */ public void setDataElements(int x, int y, Object obj, DataBuffer data) { - int offset = pixelStride*x + scanlineStride*y; + int offset = pixelStride * x + scanlineStride * y; int[] totalBandDataOffsets = new int[numBands]; int[] bankOffsets = data.getOffsets(); - for (int b=0; b<numBands; b++) - totalBandDataOffsets[b] = - bandOffsets[b]+bankOffsets[bankIndices[b]] + offset; + for (int b = 0; b < numBands; b++) + totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]] + + offset; switch (getTransferType()) { case DataBuffer.TYPE_BYTE: - { - DataBufferByte out = (DataBufferByte) data; - byte[] in = (byte[]) obj; - - for (int b=0; b<numBands; b++) - out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; - - return; - } + { + DataBufferByte out = (DataBufferByte) data; + byte[] in = (byte[]) obj; + + for (int b = 0; b < numBands; b++) + out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; + + return; + } case DataBuffer.TYPE_USHORT: - { - DataBufferUShort out = (DataBufferUShort) data; - short[] in = (short[]) obj; - - for (int b=0; b<numBands; b++) - out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; - - return; - } + { + DataBufferUShort out = (DataBufferUShort) data; + short[] in = (short[]) obj; + + for (int b = 0; b < numBands; b++) + out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; + + return; + } case DataBuffer.TYPE_SHORT: - { - DataBufferShort out = (DataBufferShort) data; - short[] in = (short[]) obj; - - for (int b=0; b<numBands; b++) - out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; - - return; - } + { + DataBufferShort out = (DataBufferShort) data; + short[] in = (short[]) obj; + + for (int b = 0; b < numBands; b++) + out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; + + return; + } case DataBuffer.TYPE_INT: - { - DataBufferInt out = (DataBufferInt) data; - int[] in = (int[]) obj; - - for (int b=0; b<numBands; b++) - out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; - - return; - } + { + DataBufferInt out = (DataBufferInt) data; + int[] in = (int[]) obj; + + for (int b = 0; b < numBands; b++) + out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; + + return; + } case DataBuffer.TYPE_FLOAT: - { - DataBufferFloat out = (DataBufferFloat) data; - float[] in = (float[]) obj; - - for (int b=0; b<numBands; b++) - out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; - - return; - } + { + DataBufferFloat out = (DataBufferFloat) data; + float[] in = (float[]) obj; + + for (int b = 0; b < numBands; b++) + out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; + + return; + } case DataBuffer.TYPE_DOUBLE: - { - DataBufferDouble out = (DataBufferDouble) data; - double[] in = (double[]) obj; - - for (int b=0; b<numBands; b++) - out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; - - return; - } + { + DataBufferDouble out = (DataBufferDouble) data; + double[] in = (double[]) obj; + + for (int b = 0; b < numBands; b++) + out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; + + return; + } default: - throw new UnsupportedOperationException("transfer type not " + - "implemented"); + throw new UnsupportedOperationException("transfer type not " + + "implemented"); } } + /** + * Sets the sample values for the pixel at location <code>(x, y)</code> + * stored in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param iArray the pixel sample values (<code>null</code> not permitted). + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getPixel(int, int, int[], DataBuffer) + */ public void setPixel(int x, int y, int[] iArray, DataBuffer data) { - int offset = pixelStride*x + scanlineStride*y; - for (int b=0; b<numBands; b++) - data.setElem(bankIndices[b], offset+bandOffsets[b], iArray[b]); + int offset = pixelStride * x + scanlineStride * y; + for (int b = 0; b < numBands; b++) + data.setElem(bankIndices[b], offset + bandOffsets[b], iArray[b]); } + /** + * Sets the sample value for band <code>b</code> of the pixel at location + * <code>(x, y)</code> in the specified data buffer. + * + * @param x the x-coordinate. + * @param y the y-coordinate. + * @param b the band index. + * @param s the sample value. + * @param data the data buffer (<code>null</code> not permitted). + * + * @see #getSample(int, int, int, DataBuffer) + */ public void setSample(int x, int y, int b, int s, DataBuffer data) { data.setElem(bankIndices[b], getOffset(x, y, b), s); } + + /** + * Tests this sample model for equality with an arbitrary object. Returns + * <code>true</code> if and only if: + * <ul> + * <li><code>obj</code> is not <code>null</code>;</li> + * <li><code>obj</code> is an instance of <code>ComponentSampleModel</code>; + * </li> + * <li>both models have the same values for the <code>dataType</code>, + * <code>width</code>, <code>height</code>, <code>pixelStride</code>, + * <code>scanlineStride</code>, <code>bandOffsets</code> and + * <code>bankIndices</code> fields.</li> + * </ul> + * + * @param obj the object to test (<code>null</code> permitted). + * + * @return <code>true</code> if this sample model is equal to + * <code>obj</code>, and <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + if (! (obj instanceof ComponentSampleModel)) + return false; + ComponentSampleModel that = (ComponentSampleModel) obj; + if (this.dataType != that.dataType) + return false; + if (this.width != that.width) + return false; + if (this.height != that.height) + return false; + if (this.pixelStride != that.pixelStride) + return false; + if (this.scanlineStride != that.scanlineStride) + return false; + if (! Arrays.equals(this.bandOffsets, that.bandOffsets)) + return false; + if (! Arrays.equals(this.bankIndices, that.bankIndices)) + return false; + // couldn't find any difference, so... + return true; + } + + /** + * Returns a hash code for this sample model. + * + * @return The hash code. + */ + public int hashCode() + { + // this computation is based on the method described in Chapter 3 + // of Joshua Bloch's Effective Java... + int result = 17; + result = 37 * result + dataType; + result = 37 * result + width; + result = 37 * result + height; + result = 37 * result + pixelStride; + result = 37 * result + scanlineStride; + for (int i = 0; i < bandOffsets.length; i++) + result = 37 * result + bandOffsets[i]; + for (int i = 0; i < bankIndices.length; i++) + result = 37 * result + bankIndices[i]; + return result; + } } diff --git a/libjava/classpath/java/awt/image/ConvolveOp.java b/libjava/classpath/java/awt/image/ConvolveOp.java index 49ca2a6..1f73f75 100644 --- a/libjava/classpath/java/awt/image/ConvolveOp.java +++ b/libjava/classpath/java/awt/image/ConvolveOp.java @@ -110,7 +110,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, * java.awt.image.BufferedImage) */ - public BufferedImage filter(BufferedImage src, BufferedImage dst) + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { if (src == dst) throw new IllegalArgumentException(); @@ -163,7 +163,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.RasterOp#getRenderingHints() */ - public RenderingHints getRenderingHints() + public final RenderingHints getRenderingHints() { return hints; } @@ -181,7 +181,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp * * @return The convolution kernel. */ - public Kernel getKernel() + public final Kernel getKernel() { return (Kernel) kernel.clone(); } @@ -190,7 +190,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, * java.awt.image.WritableRaster) */ - public WritableRaster filter(Raster src, WritableRaster dest) { + public final WritableRaster filter(Raster src, WritableRaster dest) { if (src == dest) throw new IllegalArgumentException(); if (src.getWidth() < kernel.getWidth() || @@ -309,7 +309,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) */ - public Rectangle2D getBounds2D(BufferedImage src) + public final Rectangle2D getBounds2D(BufferedImage src) { return src.getRaster().getBounds(); } @@ -317,7 +317,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) */ - public Rectangle2D getBounds2D(Raster src) + public final Rectangle2D getBounds2D(Raster src) { return src.getBounds(); } @@ -330,7 +330,7 @@ public class ConvolveOp implements BufferedImageOp, RasterOp * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, * java.awt.geom.Point2D) */ - public Point2D getPoint2D(Point2D src, Point2D dst) + public final Point2D getPoint2D(Point2D src, Point2D dst) { if (dst == null) return (Point2D)src.clone(); dst.setLocation(src); diff --git a/libjava/classpath/java/awt/image/DirectColorModel.java b/libjava/classpath/java/awt/image/DirectColorModel.java index 4f37151..579dc97 100644 --- a/libjava/classpath/java/awt/image/DirectColorModel.java +++ b/libjava/classpath/java/awt/image/DirectColorModel.java @@ -167,7 +167,7 @@ public class DirectColorModel extends PackedColorModel private int extractAndNormalizeSample(int pixel, int component) { int value = extractAndScaleSample(pixel, component); - if (hasAlpha() && isAlphaPremultiplied()) + if (hasAlpha() && isAlphaPremultiplied() && getAlpha(pixel) != 0) value = value*255/getAlpha(pixel); return value; } diff --git a/libjava/classpath/java/awt/image/LookupOp.java b/libjava/classpath/java/awt/image/LookupOp.java index f131daa..46e72fe 100644 --- a/libjava/classpath/java/awt/image/LookupOp.java +++ b/libjava/classpath/java/awt/image/LookupOp.java @@ -81,7 +81,7 @@ public class LookupOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.BufferedImageOp#filter(java.awt.image.BufferedImage, java.awt.image.BufferedImage) */ - public BufferedImage filter(BufferedImage src, BufferedImage dst) + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { if (src.getColorModel() instanceof IndexColorModel) throw new IllegalArgumentException("LookupOp.filter: IndexColorModel " @@ -149,7 +149,7 @@ public class LookupOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.BufferedImageOp#getBounds2D(java.awt.image.BufferedImage) */ - public Rectangle2D getBounds2D(BufferedImage src) + public final Rectangle2D getBounds2D(BufferedImage src) { return src.getRaster().getBounds(); } @@ -173,7 +173,7 @@ public class LookupOp implements BufferedImageOp, RasterOp * @param dst The destination point. * @see java.awt.image.RasterOp#getPoint2D(java.awt.geom.Point2D, java.awt.geom.Point2D) */ - public Point2D getPoint2D(Point2D src, Point2D dst) + public final Point2D getPoint2D(Point2D src, Point2D dst) { if (dst == null) return (Point2D) src.clone(); @@ -183,7 +183,7 @@ public class LookupOp implements BufferedImageOp, RasterOp } /** Return the LookupTable for this op. */ - public LookupTable getTable() + public final LookupTable getTable() { return lut; } @@ -191,7 +191,7 @@ public class LookupOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.RasterOp#getRenderingHints() */ - public RenderingHints getRenderingHints() + public final RenderingHints getRenderingHints() { return hints; } @@ -209,7 +209,7 @@ public class LookupOp implements BufferedImageOp, RasterOp * component but not the same as src and dest. * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, java.awt.image.WritableRaster) */ - public WritableRaster filter(Raster src, WritableRaster dest) + public final WritableRaster filter(Raster src, WritableRaster dest) { if (dest == null) // Allocate a raster if needed @@ -236,7 +236,7 @@ public class LookupOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.RasterOp#getBounds2D(java.awt.image.Raster) */ - public Rectangle2D getBounds2D(Raster src) + public final Rectangle2D getBounds2D(Raster src) { return src.getBounds(); } diff --git a/libjava/classpath/java/awt/image/ReplicateScaleFilter.java b/libjava/classpath/java/awt/image/ReplicateScaleFilter.java index d76f9db..6d5099d 100644 --- a/libjava/classpath/java/awt/image/ReplicateScaleFilter.java +++ b/libjava/classpath/java/awt/image/ReplicateScaleFilter.java @@ -46,7 +46,6 @@ import java.util.Hashtable; * exact method is not defined by Sun but some sort of fast Box filter should * probably be correct. * <br> - * Currently this filter does nothing and needs to be implemented. * * @author C. Brian Jones (cbj@gnu.org) */ diff --git a/libjava/classpath/java/awt/image/RescaleOp.java b/libjava/classpath/java/awt/image/RescaleOp.java index 35b42f7..d5b2969 100644 --- a/libjava/classpath/java/awt/image/RescaleOp.java +++ b/libjava/classpath/java/awt/image/RescaleOp.java @@ -93,7 +93,7 @@ public class RescaleOp implements BufferedImageOp, RasterOp /* (non-Javadoc) * @see java.awt.image.BufferedImageOp#getRenderingHints() */ - public RenderingHints getRenderingHints() + public final RenderingHints getRenderingHints() { return hints; } diff --git a/libjava/classpath/java/awt/image/SampleModel.java b/libjava/classpath/java/awt/image/SampleModel.java index 1159662..6e3fd40 100644 --- a/libjava/classpath/java/awt/image/SampleModel.java +++ b/libjava/classpath/java/awt/image/SampleModel.java @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2001, 2002, 2005 Free Software Foundation +/* Copyright (C) 2000, 2001, 2002, 2005, 2006, Free Software Foundation This file is part of GNU Classpath. @@ -57,15 +57,43 @@ public abstract class SampleModel */ protected int dataType; + /** + * Creates a new sample model with the specified attributes. + * + * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, + * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, + * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT}, + * {@link DataBuffer#TYPE_DOUBLE} or {@link DataBuffer#TYPE_UNDEFINED}). + * @param w the width in pixels (must be greater than zero). + * @param h the height in pixels (must be greater than zero). + * @param numBands the number of bands (must be greater than zero). + * + * @throws IllegalArgumentException if <code>dataType</code> is not one of + * the listed values. + * @throws IllegalArgumentException if <code>w</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>h</code> is less than or equal + * to zero. + * @throws IllegalArgumentException if <code>w * h</code> is greater than + * {@link Integer#MAX_VALUE}. + */ public SampleModel(int dataType, int w, int h, int numBands) { + if (dataType != DataBuffer.TYPE_UNDEFINED) + if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_DOUBLE) + throw new IllegalArgumentException("Unrecognised 'dataType' argument."); + if ((w <= 0) || (h <= 0)) throw new IllegalArgumentException((w <= 0 ? " width<=0" : " width is ok") - +(h <= 0 ? " height<=0" : " height is ok")); - - // FIXME: How can an int be greater than Integer.MAX_VALUE? - // FIXME: How do we identify an unsupported data type? - + + (h <= 0 ? " height<=0" : " height is ok")); + + long area = (long) w * (long) h; + if (area > Integer.MAX_VALUE) + throw new IllegalArgumentException("w * h exceeds Integer.MAX_VALUE."); + + if (numBands <= 0) + throw new IllegalArgumentException("Requires numBands > 0."); + this.dataType = dataType; this.width = w; this.height = h; @@ -102,8 +130,10 @@ public abstract class SampleModel public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { - if (iArray == null) iArray = new int[numBands]; - for (int b=0; b<numBands; b++) iArray[b] = getSample(x, y, b, data); + if (iArray == null) + iArray = new int[numBands]; + for (int b = 0; b < numBands; b++) + iArray[b] = getSample(x, y, b, data); return iArray; } @@ -121,94 +151,95 @@ public abstract class SampleModel * DataBuffer.TYPE_USHORT, then a short[] object is returned. */ public abstract Object getDataElements(int x, int y, Object obj, - DataBuffer data); + DataBuffer data); public Object getDataElements(int x, int y, int w, int h, Object obj, - DataBuffer data) + DataBuffer data) { - int size = w*h; + int size = w * h; int numDataElements = getNumDataElements(); - int dataSize = numDataElements*size; + int dataSize = numDataElements * size; if (obj == null) { - switch (getTransferType()) - { - case DataBuffer.TYPE_BYTE: - obj = new byte[dataSize]; - break; - case DataBuffer.TYPE_USHORT: - obj = new short[dataSize]; - break; - case DataBuffer.TYPE_INT: - obj = new int[dataSize]; - break; - default: - // Seems like the only sensible thing to do. - throw new ClassCastException(); - } + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + obj = new byte[dataSize]; + break; + case DataBuffer.TYPE_USHORT: + obj = new short[dataSize]; + break; + case DataBuffer.TYPE_INT: + obj = new int[dataSize]; + break; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } } Object pixelData = null; int outOffset = 0; - for (int yy = y; yy<(y+h); yy++) + for (int yy = y; yy < (y + h); yy++) { - for (int xx = x; xx<(x+w); xx++) - { - pixelData = getDataElements(xx, yy, pixelData, data); - System.arraycopy(pixelData, 0, obj, outOffset, - numDataElements); - outOffset += numDataElements; - } + for (int xx = x; xx < (x + w); xx++) + { + pixelData = getDataElements(xx, yy, pixelData, data); + System.arraycopy(pixelData, 0, obj, outOffset, + numDataElements); + outOffset += numDataElements; + } } return obj; } public abstract void setDataElements(int x, int y, Object obj, - DataBuffer data); + DataBuffer data); public void setDataElements(int x, int y, int w, int h, - Object obj, DataBuffer data) + Object obj, DataBuffer data) { - int size = w*h; + int size = w * h; int numDataElements = getNumDataElements(); - int dataSize = numDataElements*size; + int dataSize = numDataElements * size; Object pixelData; switch (getTransferType()) { case DataBuffer.TYPE_BYTE: - pixelData = new byte[numDataElements]; - break; + pixelData = new byte[numDataElements]; + break; case DataBuffer.TYPE_USHORT: - pixelData = new short[numDataElements]; - break; + pixelData = new short[numDataElements]; + break; case DataBuffer.TYPE_INT: - pixelData = new int[numDataElements]; - break; + pixelData = new int[numDataElements]; + break; default: - // Seems like the only sensible thing to do. - throw new ClassCastException(); + // Seems like the only sensible thing to do. + throw new ClassCastException(); } int inOffset = 0; - for (int yy=y; yy<(y+h); yy++) + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - System.arraycopy(obj, inOffset, pixelData, 0, - numDataElements); - setDataElements(xx, yy, pixelData, data); - inOffset += numDataElements; - } + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(obj, inOffset, pixelData, 0, + numDataElements); + setDataElements(xx, yy, pixelData, data); + inOffset += numDataElements; + } } } public float[] getPixel(int x, int y, float[] fArray, DataBuffer data) { - if (fArray == null) fArray = new float[numBands]; + if (fArray == null) + fArray = new float[numBands]; - for (int b=0; b<numBands; b++) + for (int b = 0; b < numBands; b++) { fArray[b] = getSampleFloat(x, y, b, data); } @@ -216,10 +247,11 @@ public abstract class SampleModel } public double[] getPixel(int x, int y, double[] dArray, DataBuffer data) { - if (dArray == null) dArray = new double[numBands]; - for (int b=0; b<numBands; b++) + if (dArray == null) + dArray = new double[numBands]; + for (int b = 0; b < numBands; b++) { - dArray[b] = getSampleDouble(x, y, b, data); + dArray[b] = getSampleDouble(x, y, b, data); } return dArray; } @@ -227,20 +259,21 @@ public abstract class SampleModel /* FIXME: Should it return a banded or pixel interleaved array of samples? (Assume interleaved.) */ public int[] getPixels(int x, int y, int w, int h, int[] iArray, - DataBuffer data) + DataBuffer data) { - int size = w*h; + int size = w * h; int outOffset = 0; int[] pixel = null; - if (iArray == null) iArray = new int[w*h*numBands]; - for (int yy=y; yy<(y+h); yy++) + if (iArray == null) + iArray = new int[w * h * numBands]; + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - pixel = getPixel(xx, yy, pixel, data); - System.arraycopy(pixel, 0, iArray, outOffset, numBands); - outOffset += numBands; - } + for (int xx = x; xx < (x + w); xx++) + { + pixel = getPixel(xx, yy, pixel, data); + System.arraycopy(pixel, 0, iArray, outOffset, numBands); + outOffset += numBands; + } } return iArray; } @@ -248,20 +281,20 @@ public abstract class SampleModel /* FIXME: Should it return a banded or pixel interleaved array of samples? (Assume interleaved.) */ public float[] getPixels(int x, int y, int w, int h, float[] fArray, - DataBuffer data) + DataBuffer data) { - int size = w*h; + int size = w * h; int outOffset = 0; float[] pixel = null; - if (fArray == null) fArray = new float[w*h*numBands]; - for (int yy=y; yy<(y+h); yy++) + if (fArray == null) fArray = new float[w * h * numBands]; + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - pixel = getPixel(xx, yy, pixel, data); - System.arraycopy(pixel, 0, fArray, outOffset, numBands); - outOffset += numBands; - } + for (int xx = x; xx < (x + w); xx++) + { + pixel = getPixel(xx, yy, pixel, data); + System.arraycopy(pixel, 0, fArray, outOffset, numBands); + outOffset += numBands; + } } return fArray; } @@ -269,20 +302,21 @@ public abstract class SampleModel /* FIXME: Should it return a banded or pixel interleaved array of samples? (Assume interleaved.) */ public double[] getPixels(int x, int y, int w, int h, double[] dArray, - DataBuffer data) + DataBuffer data) { - int size = w*h; + int size = w * h; int outOffset = 0; double[] pixel = null; - if (dArray == null) dArray = new double[w*h*numBands]; - for (int yy=y; yy<(y+h); yy++) + if (dArray == null) + dArray = new double[w * h * numBands]; + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - pixel = getPixel(xx, yy, pixel, data); - System.arraycopy(pixel, 0, dArray, outOffset, numBands); - outOffset += numBands; - } + for (int xx = x; xx < (x + w); xx++) + { + pixel = getPixel(xx, yy, pixel, data); + System.arraycopy(pixel, 0, dArray, outOffset, numBands); + outOffset += numBands; + } } return dArray; } @@ -300,179 +334,185 @@ public abstract class SampleModel } public int[] getSamples(int x, int y, int w, int h, int b, - int[] iArray, DataBuffer data) + int[] iArray, DataBuffer data) { - int size = w*h; + int size = w * h; int outOffset = 0; - if (iArray == null) iArray = new int[size]; - for (int yy=y; yy<(y+h); yy++) + if (iArray == null) + iArray = new int[size]; + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - iArray[outOffset++] = getSample(xx, yy, b, data); - } + for (int xx = x; xx < (x + w); xx++) + { + iArray[outOffset++] = getSample(xx, yy, b, data); + } } return iArray; } public float[] getSamples(int x, int y, int w, int h, int b, - float[] fArray, DataBuffer data) + float[] fArray, DataBuffer data) { - int size = w*h; + int size = w * h; int outOffset = 0; - if (fArray == null) fArray = new float[size]; - for (int yy=y; yy<(y+h); yy++) + if (fArray == null) + fArray = new float[size]; + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - fArray[outOffset++] = getSampleFloat(xx, yy, b, data); - } + for (int xx = x; xx < (x + w); xx++) + { + fArray[outOffset++] = getSampleFloat(xx, yy, b, data); + } } return fArray; } public double[] getSamples(int x, int y, int w, int h, int b, - double[] dArray, DataBuffer data) + double[] dArray, DataBuffer data) { - int size = w*h; + int size = w * h; int outOffset = 0; - if (dArray == null) dArray = new double[size]; - for (int yy=y; yy<(y+h); yy++) + if (dArray == null) + dArray = new double[size]; + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - dArray[outOffset++] = getSampleDouble(xx, yy, b, data); - } + for (int xx = x; xx < (x + w); xx++) + { + dArray[outOffset++] = getSampleDouble(xx, yy, b, data); + } } return dArray; } public void setPixel(int x, int y, int[] iArray, DataBuffer data) { - for (int b=0; b<numBands; b++) setSample(x, y, b, iArray[b], data); + for (int b = 0; b < numBands; b++) + setSample(x, y, b, iArray[b], data); } public void setPixel(int x, int y, float[] fArray, DataBuffer data) { - for (int b=0; b<numBands; b++) setSample(x, y, b, fArray[b], data); + for (int b = 0; b < numBands; b++) + setSample(x, y, b, fArray[b], data); } public void setPixel(int x, int y, double[] dArray, DataBuffer data) { - for (int b=0; b<numBands; b++) setSample(x, y, b, dArray[b], data); + for (int b = 0; b < numBands; b++) + setSample(x, y, b, dArray[b], data); } public void setPixels(int x, int y, int w, int h, int[] iArray, - DataBuffer data) + DataBuffer data) { int inOffset = 0; int[] pixel = new int[numBands]; - for (int yy=y; yy<(y+h); yy++) + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - System.arraycopy(iArray, inOffset, pixel, 0, numBands); - setPixel(xx, yy, pixel, data); - inOffset += numBands; - } + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(iArray, inOffset, pixel, 0, numBands); + setPixel(xx, yy, pixel, data); + inOffset += numBands; + } } } public void setPixels(int x, int y, int w, int h, float[] fArray, - DataBuffer data) + DataBuffer data) { int inOffset = 0; float[] pixel = new float[numBands]; - for (int yy=y; yy<(y+h); yy++) + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - System.arraycopy(fArray, inOffset, pixel, 0, numBands); - setPixel(xx, yy, pixel, data); - inOffset += numBands; - } + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(fArray, inOffset, pixel, 0, numBands); + setPixel(xx, yy, pixel, data); + inOffset += numBands; + } } } public void setPixels(int x, int y, int w, int h, double[] dArray, - DataBuffer data) + DataBuffer data) { int inOffset = 0; double[] pixel = new double[numBands]; - for (int yy=y; yy<(y+h); yy++) + for (int yy = y; yy < (y + h); yy++) { - for (int xx=x; xx<(x+w); xx++) - { - System.arraycopy(dArray, inOffset, pixel, 0, numBands); - setPixel(xx, yy, pixel, data); - inOffset += numBands; - } + for (int xx = x; xx < (x + w); xx++) + { + System.arraycopy(dArray, inOffset, pixel, 0, numBands); + setPixel(xx, yy, pixel, data); + inOffset += numBands; + } } } public abstract void setSample(int x, int y, int b, int s, - DataBuffer data); + DataBuffer data); public void setSample(int x, int y, int b, float s, - DataBuffer data) + DataBuffer data) { setSample(x, y, b, (int) s, data); } public void setSample(int x, int y, int b, double s, - DataBuffer data) + DataBuffer data) { setSample(x, y, b, (float) s, data); } public void setSamples(int x, int y, int w, int h, int b, - int[] iArray, DataBuffer data) + int[] iArray, DataBuffer data) { - int size = w*h; + int size = w * h; int inOffset = 0; - for (int yy=y; yy<(y+h); yy++) - for (int xx=x; xx<(x+w); xx++) - setSample(xx, yy, b, iArray[inOffset++], data); + for (int yy = y; yy < (y + h); yy++) + for (int xx = x; xx < (x + w); xx++) + setSample(xx, yy, b, iArray[inOffset++], data); } public void setSamples(int x, int y, int w, int h, int b, - float[] fArray, DataBuffer data) + float[] fArray, DataBuffer data) { - int size = w*h; + int size = w * h; + int inOffset = 0; + for (int yy = y; yy < (y + h); yy++) + for (int xx = x; xx < (x + w); xx++) + setSample(xx, yy, b, fArray[inOffset++], data); + + } + + public void setSamples(int x, int y, int w, int h, int b, + double[] dArray, DataBuffer data) { + int size = w * h; int inOffset = 0; - for (int yy=y; yy<(y+h); yy++) - for (int xx=x; xx<(x+w); xx++) - setSample(xx, yy, b, fArray[inOffset++], data); - - } - - public void setSamples(int x, int y, int w, int h, int b, - double[] dArray, DataBuffer data) { - int size = w*h; - int inOffset = 0; - for (int yy=y; yy<(y+h); yy++) - for (int xx=x; xx<(x+w); xx++) - setSample(xx, yy, b, dArray[inOffset++], data); - } - - public abstract SampleModel createCompatibleSampleModel(int w, int h); - - /** - * Return a SampleModel with a subset of the bands in this model. - * - * Selects bands.length bands from this sample model. The bands chosen - * are specified in the indices of bands[]. This also permits permuting - * the bands as well as taking a subset. Thus, giving an array with - * 1, 2, 3, ..., numbands, will give an identical sample model. - * - * @param bands Array with band indices to include. - * @return A new sample model - */ - public abstract SampleModel createSubsetSampleModel(int[] bands); - - public abstract DataBuffer createDataBuffer(); - - public abstract int[] getSampleSize(); - - public abstract int getSampleSize(int band); + for (int yy = y; yy < (y + h); yy++) + for (int xx = x; xx < (x + w); xx++) + setSample(xx, yy, b, dArray[inOffset++], data); + } + + public abstract SampleModel createCompatibleSampleModel(int w, int h); + + /** + * Return a SampleModel with a subset of the bands in this model. + * + * Selects bands.length bands from this sample model. The bands chosen + * are specified in the indices of bands[]. This also permits permuting + * the bands as well as taking a subset. Thus, giving an array with + * 1, 2, 3, ..., numbands, will give an identical sample model. + * + * @param bands Array with band indices to include. + * @return A new sample model + */ + public abstract SampleModel createSubsetSampleModel(int[] bands); + + public abstract DataBuffer createDataBuffer(); + + public abstract int[] getSampleSize(); + + public abstract int getSampleSize(int band); } diff --git a/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java b/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java index 78f3051..d8cca65 100644 --- a/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java +++ b/libjava/classpath/java/awt/image/renderable/RenderableImageProducer.java @@ -1,5 +1,5 @@ /* RenderableImageProducer.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,42 +38,129 @@ exception statement from your version. */ package java.awt.image.renderable; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; import java.awt.image.ImageConsumer; import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.util.ArrayList; +import java.util.Iterator; public class RenderableImageProducer implements ImageProducer, Runnable { + private RenderableImage image; + private RenderContext context; + private ArrayList consumers = new ArrayList(); + public RenderableImageProducer(RenderableImage image, RenderContext context) { - throw new Error("not implemented"); + this.image = image; + this.context = context; } public void setRenderContext(RenderContext context) { + this.context = context; } public void addConsumer(ImageConsumer consumer) { + synchronized (consumers) + { + if (! consumers.contains(consumer)) + consumers.add(consumer); + } } public boolean isConsumer(ImageConsumer consumer) { - return false; + synchronized (consumers) + { + return consumers.contains(consumer); + } } public void removeConsumer(ImageConsumer consumer) { + synchronized (consumers) + { + consumers.remove(consumer); + } } public void startProduction(ImageConsumer consumer) { + addConsumer(consumer); + Thread t = new Thread(this, "RenderableImageProducerWorker"); + t.start(); } public void requestTopDownLeftRightResend(ImageConsumer consumer) { + // Do nothing. The contract says we can ignore this call, so we do. } public void run() { + // This isn't ideal but it avoids fail-fast problems. + // Alternatively, we could clone 'consumers' here. + synchronized (consumers) + { + RenderedImage newImage; + if (context == null) + newImage = image.createDefaultRendering(); + else + newImage = image.createRendering(context); + Raster newData = newImage.getData(); + ColorModel colorModel = newImage.getColorModel(); + if (colorModel == null) + colorModel = ColorModel.getRGBdefault(); + SampleModel sampleModel = newData.getSampleModel(); + DataBuffer dataBuffer = newData.getDataBuffer(); + int width = newData.getWidth(); + int height = newData.getHeight(); + + // Initialize the consumers. + Iterator it = consumers.iterator(); + while (it.hasNext()) + { + ImageConsumer target = (ImageConsumer) it.next(); + target.setHints(ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEFRAME + | ImageConsumer.SINGLEPASS + | ImageConsumer.TOPDOWNLEFTRIGHT); + target.setDimensions(width, height); + } + + // Work in scan-line order. + int[] newLine = new int[width]; + int[] bands = new int[sampleModel.getNumBands()]; + for (int y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + sampleModel.getPixel(x, y, bands, dataBuffer); + newLine[x] = colorModel.getDataElement(bands, 0); + } + + // Tell the consumers about the new scan line. + it = consumers.iterator(); + while (it.hasNext()) + { + ImageConsumer target = (ImageConsumer) it.next(); + target.setPixels(0, y, width, 1, colorModel, newLine, 0, width); + } + } + + // Tell the consumers that we're done. + it = consumers.iterator(); + while (it.hasNext()) + { + ImageConsumer target = (ImageConsumer) it.next(); + target.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } } } // class RenderableImageProducer |