From: <ls...@us...> - 2008-07-17 10:12:47
|
Revision: 4304 http://jnode.svn.sourceforge.net/jnode/?rev=4304&view=rev Author: lsantha Date: 2008-07-17 10:12:06 +0000 (Thu, 17 Jul 2008) Log Message: ----------- New java.awt.Graphics implementation. Modified Paths: -------------- trunk/core/src/classpath/vm/java/awt/image/VMImageAPI.java trunk/gui/src/awt/org/jnode/awt/JNodeGraphicsEnvironment.java trunk/gui/src/awt/org/jnode/awt/VMImageAPIImpl.java trunk/gui/src/awt/org/jnode/awt/image/JNodeBufferedImage.java trunk/gui/src/awt/org/jnode/awt/swingpeers/DesktopFramePeer.java trunk/gui/src/awt/org/jnode/awt/swingpeers/SwingComponentPeer.java Added Paths: ----------- trunk/gui/src/awt/org/jnode/awt/GraphicsFactory.java trunk/gui/src/awt/org/jnode/awt/JNodeSurfaceGraphics2D.java trunk/gui/src/awt/org/jnode/awt/image/BufferedImageGraphics2D.java trunk/gui/src/awt/org/jnode/awt/util/BasicGraphics.java trunk/gui/src/awt/org/jnode/awt/util/BasicSurfaceGraphics.java trunk/gui/src/awt/org/jnode/awt/util/SurfaceGraphics2D.java Modified: trunk/core/src/classpath/vm/java/awt/image/VMImageAPI.java =================================================================== --- trunk/core/src/classpath/vm/java/awt/image/VMImageAPI.java 2008-07-17 09:55:42 UTC (rev 4303) +++ trunk/core/src/classpath/vm/java/awt/image/VMImageAPI.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -23,6 +23,7 @@ import java.awt.Graphics2D; +//todo: is it useful? /** * @author Ewout Prangsma (ep...@us...) */ Added: trunk/gui/src/awt/org/jnode/awt/GraphicsFactory.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/GraphicsFactory.java (rev 0) +++ trunk/gui/src/awt/org/jnode/awt/GraphicsFactory.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -0,0 +1,48 @@ +/* + * $ + */ +package org.jnode.awt; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import org.jnode.awt.image.JNodeBufferedImageGraphics; +import org.jnode.awt.image.BufferedImageGraphics2D; + +/** + * @author Levente S\u00e1ntha + */ +public abstract class GraphicsFactory { + public static GraphicsFactory instance; + + public static GraphicsFactory getInstance() { + if (instance == null) { + instance = new NewGraphicsFactory(); + } + return instance; + } + + public abstract Graphics2D createGraphics(BufferedImage image); + + public abstract Graphics2D createGraphics(JNodeGenericPeer<?, ?> peer); + + private static class OldGraphicsFactory extends GraphicsFactory { + public Graphics2D createGraphics(BufferedImage image) { + return new JNodeBufferedImageGraphics(image); + } + + public Graphics2D createGraphics(JNodeGenericPeer<?, ?> peer) { + return new JNodeGraphics(peer); + } + + } + + private static class NewGraphicsFactory extends GraphicsFactory { + public Graphics2D createGraphics(BufferedImage image) { + return new BufferedImageGraphics2D(image); + } + + public Graphics2D createGraphics(JNodeGenericPeer<?, ?> peer) { + return new JNodeSurfaceGraphics2D(peer); + } + } +} Modified: trunk/gui/src/awt/org/jnode/awt/JNodeGraphicsEnvironment.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/JNodeGraphicsEnvironment.java 2008-07-17 09:55:42 UTC (rev 4303) +++ trunk/gui/src/awt/org/jnode/awt/JNodeGraphicsEnvironment.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -35,7 +35,6 @@ import javax.naming.NamingException; import org.apache.log4j.Logger; import org.jnode.awt.font.FontManager; -import org.jnode.awt.image.JNodeBufferedImageGraphics; import org.jnode.awt.image.JNodeBufferedImageGraphics2D; import org.jnode.driver.Device; import org.jnode.driver.DeviceUtils; @@ -57,13 +56,13 @@ private GraphicsDevice defaultDevice; /** - * @param image + * @param image the target image * @return The graphics * @see java.awt.GraphicsEnvironment#createGraphics(java.awt.image.BufferedImage) */ public Graphics2D createGraphics(BufferedImage image) { return SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null ? - new JNodeBufferedImageGraphics2D(image) : new JNodeBufferedImageGraphics(image); + new JNodeBufferedImageGraphics2D(image) : GraphicsFactory.getInstance().createGraphics(image); /* ..future transition to SunGraphics2D based buffered image graphics Copied: trunk/gui/src/awt/org/jnode/awt/JNodeSurfaceGraphics2D.java (from rev 4301, trunk/gui/src/awt/org/jnode/awt/JNodeGraphics.java) =================================================================== --- trunk/gui/src/awt/org/jnode/awt/JNodeSurfaceGraphics2D.java (rev 0) +++ trunk/gui/src/awt/org/jnode/awt/JNodeSurfaceGraphics2D.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -0,0 +1,138 @@ +/* + * $Id$ + * + * JNode.org + * Copyright (C) 2003-2006 JNode.org + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.jnode.awt; + +import java.awt.Component; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import org.jnode.awt.util.SurfaceGraphics2D; +import org.jnode.driver.video.util.AbstractSurface; + +/** + * @author epr + */ +public class JNodeSurfaceGraphics2D extends SurfaceGraphics2D { + + private final JNodeGenericPeer component; + private final JNodeToolkit toolkit; + + /** + * Initialize a graphics for the given component + * + * @param component + */ + public JNodeSurfaceGraphics2D(JNodeGenericPeer<?, ?> component) { +// super(component.getToolkitImpl().getGraphics(), ((Component) component.getTargetComponent()).getWidth(), + // ((Component) component.getTargetComponent()).getHeight()); + super((AbstractSurface) component.getToolkitImpl().getGraphics()); + this.component = component; + this.toolkit = component.getToolkitImpl(); + } + + /** + * Initialize a graphics base on the given source. + * + * @param src + */ + public JNodeSurfaceGraphics2D(JNodeSurfaceGraphics2D src) { + super(src); + this.component = src.component; + this.toolkit = src.toolkit; + } + + /** + * @return The graphics + * @see java.awt.Graphics#create() + */ + public Graphics create() { + return new JNodeSurfaceGraphics2D(this); + } + + /** + * @param font + * @return The metrics + * @see java.awt.Graphics#getFontMetrics(java.awt.Font) + */ + public FontMetrics getFontMetrics(Font font) { + return toolkit.getFontMetrics(font); + } + + /** + * @return The configuration + * @see java.awt.Graphics2D#getDeviceConfiguration() + */ + public GraphicsConfiguration getDeviceConfiguration() { + // TODO Auto-generated method stub + return null; + } + + //----- preparing Graphics2D + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() { + return toolkit.getColorModel(); + } + + /** + * Returns a WritableRaster that is used by this class to perform the + * rendering in. It is not necessary that the target surface immediately + * reflects changes in the raster. Updates to the raster are notified via + * {@link #updateRaster}. + * + * @return the destination raster + */ + protected WritableRaster getDestinationRaster() { + if (image == null) + image = new BufferedImage(((Component) component.getTargetComponent()).getWidth(), + ((Component) component.getTargetComponent()).getHeight(), BufferedImage.TYPE_INT_ARGB); + return image.getRaster(); + } + + private BufferedImage image; + + /** + * Notifies the backend that the raster has changed in the specified + * rectangular area. The raster that is provided in this method is always + * the same as the one returned in {@link #getDestinationRaster}. + * Backends that reflect changes to this raster directly don't need to do + * anything here. + * + * @param raster the updated raster, identical to the raster returned + * by {@link #getDestinationRaster()} + * @param x the upper left corner of the updated region, X coordinate + * @param y the upper lef corner of the updated region, Y coordinate + * @param w the width of the updated region + * @param h the height of the updated region + */ + protected void updateRaster(Raster raster, int x, int y, int w, int h) { + drawImage(image, 0, 0, null); + } +} Modified: trunk/gui/src/awt/org/jnode/awt/VMImageAPIImpl.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/VMImageAPIImpl.java 2008-07-17 09:55:42 UTC (rev 4303) +++ trunk/gui/src/awt/org/jnode/awt/VMImageAPIImpl.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -24,7 +24,6 @@ import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.awt.image.VMImageAPI; -import org.jnode.awt.image.JNodeBufferedImageGraphics; /** * @author Ewout Prangsma (ep...@us...) @@ -32,7 +31,7 @@ public class VMImageAPIImpl implements VMImageAPI { public Graphics2D createGraphics(BufferedImage image) { - return new JNodeBufferedImageGraphics(image); + return GraphicsFactory.getInstance().createGraphics(image); } } Copied: trunk/gui/src/awt/org/jnode/awt/image/BufferedImageGraphics2D.java (from rev 4301, trunk/gui/src/awt/org/jnode/awt/image/JNodeBufferedImageGraphics.java) =================================================================== --- trunk/gui/src/awt/org/jnode/awt/image/BufferedImageGraphics2D.java (rev 0) +++ trunk/gui/src/awt/org/jnode/awt/image/BufferedImageGraphics2D.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -0,0 +1,89 @@ +/* + * $Id$ + * + * JNode.org + * Copyright (C) 2003-2006 JNode.org + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.jnode.awt.image; + +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.WritableRaster; +import org.jnode.awt.util.SurfaceGraphics2D; + +/** + * @author epr + */ +public class BufferedImageGraphics2D extends SurfaceGraphics2D { + + private final BufferedImage image; + + /** + * @param image the target image + */ + public BufferedImageGraphics2D(BufferedImage image) { + //super(new BufferedImageSurface(image), image.getWidth(), image.getHeight()); + super(new BufferedImageSurface(image)); + this.image = image; + } + + /** + * @param src + */ + public BufferedImageGraphics2D(BufferedImageGraphics2D src) { + super(src); + this.image = src.image; + } + + /** + * @return The graphics + * @see java.awt.Graphics#create() + */ + public Graphics create() { + return new BufferedImageGraphics2D(this); + } + + /** + * @return The configuration + * @see java.awt.Graphics2D#getDeviceConfiguration() + */ + public GraphicsConfiguration getDeviceConfiguration() { + // TODO Auto-generated method stub + return null; + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() { + return image.getColorModel(); + } + + /** + * Returns a WritableRaster that is used by this class to perform the rendering on. + * + * @return the destination raster + */ + protected WritableRaster getDestinationRaster() { + return image.getRaster(); + } +} Modified: trunk/gui/src/awt/org/jnode/awt/image/JNodeBufferedImage.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/image/JNodeBufferedImage.java 2008-07-17 09:55:42 UTC (rev 4303) +++ trunk/gui/src/awt/org/jnode/awt/image/JNodeBufferedImage.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -28,6 +28,7 @@ import java.awt.image.IndexColorModel; import java.awt.image.WritableRaster; import java.util.Hashtable; +import org.jnode.awt.GraphicsFactory; /** * @author epr @@ -70,6 +71,6 @@ */ public Graphics2D createGraphics() { return SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null ? - new JNodeBufferedImageGraphics2D(this) : new JNodeBufferedImageGraphics(this); + new JNodeBufferedImageGraphics2D(this) : GraphicsFactory.getInstance().createGraphics(this); } } Modified: trunk/gui/src/awt/org/jnode/awt/swingpeers/DesktopFramePeer.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/swingpeers/DesktopFramePeer.java 2008-07-17 09:55:42 UTC (rev 4303) +++ trunk/gui/src/awt/org/jnode/awt/swingpeers/DesktopFramePeer.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -51,8 +51,8 @@ import java.awt.peer.FramePeer; import org.apache.log4j.Logger; import org.jnode.awt.JNodeGenericPeer; -import org.jnode.awt.JNodeGraphics; import org.jnode.awt.JNodeGraphics2D; +import org.jnode.awt.GraphicsFactory; import sun.awt.CausedFocusEvent; /** @@ -319,7 +319,7 @@ */ public Graphics getGraphics() { return SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null ? - new JNodeGraphics2D(this) : new JNodeGraphics(this); + new JNodeGraphics2D(this) : GraphicsFactory.getInstance().createGraphics(this); } /** Modified: trunk/gui/src/awt/org/jnode/awt/swingpeers/SwingComponentPeer.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/swingpeers/SwingComponentPeer.java 2008-07-17 09:55:42 UTC (rev 4303) +++ trunk/gui/src/awt/org/jnode/awt/swingpeers/SwingComponentPeer.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -40,6 +40,7 @@ import java.awt.Rectangle; import java.awt.event.ComponentEvent; import java.awt.event.FocusEvent; +import java.awt.event.MouseEvent; import java.awt.event.PaintEvent; import java.awt.image.ColorModel; import java.awt.image.ImageObserver; @@ -52,8 +53,8 @@ import java.security.PrivilegedAction; import org.apache.log4j.Logger; import org.jnode.awt.JNodeGenericPeer; -import org.jnode.awt.JNodeGraphics; import org.jnode.awt.JNodeGraphics2D; +import org.jnode.awt.GraphicsFactory; import sun.awt.CausedFocusEvent; /** @@ -170,7 +171,7 @@ final int width = peerComponent.getWidth(); final int height = peerComponent.getHeight(); Graphics g = SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null ? - new JNodeGraphics2D(this) : new JNodeGraphics(this); + new JNodeGraphics2D(this) : GraphicsFactory.getInstance().createGraphics(this); g.translate(x, y); g.clipRect(0, 0, width, height); @@ -225,8 +226,12 @@ //Point p = component.getLocationOnScreen(); //g.translate(p.x, p.y); if (event.getID() == PaintEvent.PAINT) { + if (!(targetComponent instanceof java.awt.Window)) + peerComponent.paint(g); targetComponent.paint(g); } else { + if (!(targetComponent instanceof java.awt.Window)) + peerComponent.update(g); targetComponent.update(g); } //g.translate(-p.x, -p.y); @@ -242,13 +247,25 @@ switch (id) { case PaintEvent.PAINT: case PaintEvent.UPDATE: { - //processPaintEvent((PaintEvent)event); + processPaintEvent((PaintEvent) event); break; } default: { if (event.getSource() == targetComponent) { event.setSource(peerComponent); } + if (event.getID() == MouseEvent.MOUSE_ENTERED) { + Object source = event.getSource(); + if (source instanceof Component) { + Component comp = (Component) source; + Cursor cur = comp.getCursor(); + if (cur != null) { + comp.setCursor(cur); + } else { + comp.setCursor(Cursor.getDefaultCursor()); + } + } + } ((ISwingPeer<awtT>) peerComponent).processAWTEvent(event); break; } @@ -289,8 +306,11 @@ } public final void paint(Graphics g) { - //peerComponent.paint(g); - toolkit.postEvent(new PaintEvent(targetComponent, PaintEvent.PAINT, targetComponent.getBounds())); + if (!(targetComponent instanceof java.awt.Window)) { + peerComponent.paint(g); + targetComponent.paint(g); + } else + toolkit.postEvent(new PaintEvent(targetComponent, PaintEvent.PAINT, targetComponent.getBounds())); } // Deprecated @@ -474,7 +494,12 @@ // Cursor public final void updateCursorImmediately() { - toolkit.updateCursor(peerComponent.getCursor()); + + Cursor cur = targetComponent.getCursor(); +// org.jnode.vm.Unsafe.debug("JNodeToolkit.updateCursor()-2 " + cur + " for " + targetComponent + "\n"); +// org.jnode.vm.Unsafe.debugStackTrace(100); + peerComponent.setCursor(cur); + toolkit.updateCursor(cur); } /** Added: trunk/gui/src/awt/org/jnode/awt/util/BasicGraphics.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/util/BasicGraphics.java (rev 0) +++ trunk/gui/src/awt/org/jnode/awt/util/BasicGraphics.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -0,0 +1,332 @@ +/* + * $ + */ +package org.jnode.awt.util; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.geom.Rectangle2D; + +/** + * @author Levente S\u00e1ntha + */ +public abstract class BasicGraphics extends Graphics { + protected Rectangle clip; + protected Point origin = new Point(); + protected Color color = Color.BLACK; + protected Font font = new Font("Luxi Sans", Font.PLAIN, 10); + + protected BasicGraphics() { + + } + + protected BasicGraphics(BasicGraphics g) { + this.clip = g.clip.getBounds(); + this.origin = g.origin.getLocation(); + this.color = g.color; + this.font = g.font; + } + + /** + * Intersects the current clip with the specified rectangle. + * The resulting clipping area is the intersection of the current + * clipping area and the specified rectangle. If there is no + * current clipping area, either because the clip has never been + * set, or the clip has been cleared using <code>setClip(null)</code>, + * the specified rectangle becomes the new clip. + * This method sets the user clip, which is independent of the + * clipping associated with device bounds and window visibility. + * This method can only be used to make the current clip smaller. + * To set the current clip larger, use any of the setClip methods. + * Rendering operations have no effect outside of the clipping area. + * + * @param x the x coordinate of the rectangle to intersect the clip with + * @param y the y coordinate of the rectangle to intersect the clip with + * @param width the width of the rectangle to intersect the clip with + * @param height the height of the rectangle to intersect the clip with + * @see #setClip(int, int, int, int) + * @see #setClip(java.awt.Shape) + */ + public void clipRect(int x, int y, int width, int height) { + Rectangle r = new Rectangle(x, y, width, height); + _transform(r); + if (clip == null) + clip = r; + else + clip = clip.intersection(r); + + if (this.clip.width == 0 && this.clip.height == 0) { + org.jnode.vm.Unsafe.debug("SimpleSurfaceGraphics: zero clip " + clip + "\n"); + org.jnode.vm.Unsafe.debugStackTrace(); + } + } + + /** + * Disposes of this graphics context and releases + * any system resources that it is using. + * A <code>Graphics</code> object cannot be used after + * <code>dispose</code>has been called. + * <p/> + * When a Java program runs, a large number of <code>Graphics</code> + * objects can be created within a short time frame. + * Although the finalization process of the garbage collector + * also disposes of the same system resources, it is preferable + * to manually free the associated resources by calling this + * method rather than to rely on a finalization process which + * may not run to completion for a long period of time. + * <p/> + * Graphics objects which are provided as arguments to the + * <code>paint</code> and <code>update</code> methods + * of components are automatically released by the system when + * those methods return. For efficiency, programmers should + * call <code>dispose</code> when finished using + * a <code>Graphics</code> object only if it was created + * directly from a component or another <code>Graphics</code> object. + * + * @see java.awt.Graphics#finalize + * @see java.awt.Component#paint + * @see java.awt.Component#update + * @see java.awt.Component#getGraphics + * @see java.awt.Graphics#create + */ + public void dispose() { + + } + + /** + * Gets the current clipping area. + * This method returns the user clip, which is independent of the + * clipping associated with device bounds and window visibility. + * If no clip has previously been set, or if the clip has been + * cleared using <code>setClip(null)</code>, this method returns + * <code>null</code>. + * + * @return a <code>Shape</code> object representing the + * current clipping area, or <code>null</code> if + * no clip is set. + * @see java.awt.Graphics#getClipBounds + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(int, int, int, int) + * @see java.awt.Graphics#setClip(java.awt.Shape) + * @since JDK1.1 + */ + public Shape getClip() { + if (clip == null) + return null; + + Rectangle c = new Rectangle(clip); + i_transform(c); + return c; + } + + /** + * Returns the bounding rectangle of the current clipping area. + * This method refers to the user clip, which is independent of the + * clipping associated with device bounds and window visibility. + * If no clip has previously been set, or if the clip has been + * cleared using <code>setClip(null)</code>, this method returns + * <code>null</code>. + * The coordinates in the rectangle are relative to the coordinate + * system origin of this graphics context. + * + * @return the bounding rectangle of the current clipping area, + * or <code>null</code> if no clip is set. + * @see java.awt.Graphics#getClip + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(int, int, int, int) + * @see java.awt.Graphics#setClip(java.awt.Shape) + * @since JDK1.1 + */ + public Rectangle getClipBounds() { + if (clip == null) + return null; + + Rectangle c = new Rectangle(clip); + i_transform(c); + return c; + } + + /** + * Gets this graphics context's current color. + * + * @return this graphics context's current color. + * @see java.awt.Color + * @see java.awt.Graphics#setColor(java.awt.Color) + */ + public Color getColor() { + return color; + } + + /** + * Gets the current font. + * + * @return this graphics context's current font. + * @see java.awt.Font + * @see java.awt.Graphics#setFont(java.awt.Font) + */ + public Font getFont() { + return font; + } + + /** + * Gets the font metrics for the specified font. + * + * @param f the specified font + * @return the font metrics for the specified font. + * @see java.awt.Graphics#getFont + * @see java.awt.FontMetrics + * @see java.awt.Graphics#getFontMetrics() + */ + public FontMetrics getFontMetrics(Font f) { + return Toolkit.getDefaultToolkit().getFontMetrics(font); + } + + /** + * Sets the current clipping area to an arbitrary clip shape. + * Not all objects that implement the <code>Shape</code> + * interface can be used to set the clip. The only + * <code>Shape</code> objects that are guaranteed to be + * supported are <code>Shape</code> objects that are + * obtained via the <code>getClip</code> method and via + * <code>Rectangle</code> objects. This method sets the + * user clip, which is independent of the clipping associated + * with device bounds and window visibility. + * + * @param clip the <code>Shape</code> to use to set the clip + * @see java.awt.Graphics#getClip() + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(int, int, int, int) + * @since JDK1.1 + */ + public void setClip(Shape clip) { + if (clip instanceof Rectangle) { + this.clip = new Rectangle((Rectangle) clip); + _transform(this.clip); + } else if (clip instanceof Rectangle2D) { + this.clip = clip.getBounds(); + _transform(this.clip); + } + if (this.clip.width == 0 && this.clip.height == 0) { + org.jnode.vm.Unsafe.debug("SimpleSurfaceGraphics: zero clip " + clip + "\n"); + org.jnode.vm.Unsafe.debugStackTrace(); + } + } + + /** + * Sets the current clip to the rectangle specified by the given + * coordinates. This method sets the user clip, which is + * independent of the clipping associated with device bounds + * and window visibility. + * Rendering operations have no effect outside of the clipping area. + * + * @param x the <i>x</i> coordinate of the new clip rectangle. + * @param y the <i>y</i> coordinate of the new clip rectangle. + * @param width the width of the new clip rectangle. + * @param height the height of the new clip rectangle. + * @see java.awt.Graphics#getClip + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(java.awt.Shape) + * @since JDK1.1 + */ + public void setClip(int x, int y, int width, int height) { + this.clip = new Rectangle(x, y, width, height); + _transform(this.clip); + if (clip.width == 0 && clip.height == 0) { + org.jnode.vm.Unsafe.debug("SimpleSurfaceGraphics: zero clip " + clip + "\n"); + org.jnode.vm.Unsafe.debugStackTrace(); + } + } + + /** + * Sets this graphics context's current color to the specified + * color. All subsequent graphics operations using this graphics + * context use this specified color. + * + * @param c the new rendering color. + * @see java.awt.Color + * @see java.awt.Graphics#getColor + */ + public void setColor(Color c) { + if (c != null) + this.color = c; + } + + /** + * Sets this graphics context's font to the specified font. + * All subsequent text operations using this graphics context + * use this font. A null argument is silently ignored. + * + * @param font the font. + * @see java.awt.Graphics#getFont + * @see java.awt.Graphics#drawString(String, int, int) + * @see java.awt.Graphics#drawBytes(byte[], int, int, int, int) + * @see java.awt.Graphics#drawChars(char[], int, int, int, int) + */ + public void setFont(Font font) { + if (font != null) + this.font = font; + } + + /** + * Sets the paint mode of this graphics context to overwrite the + * destination with this graphics context's current color. + * This sets the logical pixel operation function to the paint or + * overwrite mode. All subsequent rendering operations will + * overwrite the destination with the current color. + */ + public void setPaintMode() { + //todo + } + + /** + * Sets the paint mode of this graphics context to alternate between + * this graphics context's current color and the new specified color. + * This specifies that logical pixel operations are performed in the + * XOR mode, which alternates pixels between the current color and + * a specified XOR color. + * <p/> + * When drawing operations are performed, pixels which are the + * current color are changed to the specified color, and vice versa. + * <p/> + * Pixels that are of colors other than those two colors are changed + * in an unpredictable but reversible manner; if the same figure is + * drawn twice, then all pixels are restored to their original values. + * + * @param c1 the XOR alternation color + */ + public void setXORMode(Color c1) { + //todo + } + + /** + * Translates the origin of the graphics context to the point + * (<i>x</i>, <i>y</i>) in the current coordinate system. + * Modifies this graphics context so that its new origin corresponds + * to the point (<i>x</i>, <i>y</i>) in this graphics context's + * original coordinate system. All coordinates used in subsequent + * rendering operations on this graphics context will be relative + * to this new origin. + * + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + */ + public void translate(int x, int y) { + origin.translate(x, y); + } + + protected void _transform(Rectangle r) { + r.x = r.x + origin.x; + r.y = r.y + origin.y; + } + + protected void i_transform(Rectangle r) { + r.x = r.x - origin.x; + r.y = r.y - origin.y; + } +} Added: trunk/gui/src/awt/org/jnode/awt/util/BasicSurfaceGraphics.java =================================================================== --- trunk/gui/src/awt/org/jnode/awt/util/BasicSurfaceGraphics.java (rev 0) +++ trunk/gui/src/awt/org/jnode/awt/util/BasicSurfaceGraphics.java 2008-07-17 10:12:06 UTC (rev 4304) @@ -0,0 +1,1037 @@ +/* + * $ + */ +package org.jnode.awt.util; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.image.AreaAveragingScaleFilter; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.CropImageFilter; +import java.awt.image.DirectColorModel; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.IndexColorModel; +import java.awt.image.PixelGrabber; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.text.AttributedCharacterIterator; +import org.jnode.awt.JNodeToolkit; +import org.jnode.driver.video.Surface; +import org.jnode.driver.video.util.AbstractSurface; +import sun.awt.image.ToolkitImage; + +/** + * @author Levente S\u00e1ntha + */ +public class BasicSurfaceGraphics extends BasicGraphics { + private final AbstractSurface surface; + private int mode = Surface.PAINT_MODE; + + protected BasicSurfaceGraphics(AbstractSurface surface) { + this.surface = surface; + } + + protected BasicSurfaceGraphics(BasicSurfaceGraphics g) { + super(g); + this.surface = g.surface; + this.mode = g.mode; + } + + /** + * Clears the specified rectangle by filling it with the background + * color of the current drawing surface. This operation does not + * use the current paint mode. + * <p/> + * Beginning with Java 1.1, the background color + * of offscreen images may be system dependent. Applications should + * use <code>setColor</code> followed by <code>fillRect</code> to + * ensure that an offscreen image is cleared to a specific color. + * + * @param x the <i>x</i> coordinate of the rectangle to clear. + * @param y the <i>y</i> coordinate of the rectangle to clear. + * @param width the width of the rectangle to clear. + * @param height the height of the rectangle to clear. + * @see java.awt.Graphics#fillRect(int, int, int, int) + * @see java.awt.Graphics#drawRect + * @see java.awt.Graphics#setColor(java.awt.Color) + * @see java.awt.Graphics#setPaintMode + * @see java.awt.Graphics#setXORMode(java.awt.Color) + */ + public void clearRect(int x, int y, int width, int height) { + Rectangle r = new Rectangle(x, y, width, height); + _transform(r); + if (clip != null) + r = clip.intersection(r); + + surface.fillRect(r.x, r.y, r.width, r.height, Color.BLACK.getRGB(), Surface.PAINT_MODE); + surface.update(r.x, r.y, r.width, r.height); + } + + /** + * Copies an area of the component by a distance specified by + * <code>dx</code> and <code>dy</code>. From the point specified + * by <code>x</code> and <code>y</code>, this method + * copies downwards and to the right. To copy an area of the + * component to the left or upwards, specify a negative value for + * <code>dx</code> or <code>dy</code>. + * If a portion of the source rectangle lies outside the bounds + * of the component, or is obscured by another window or component, + * <code>copyArea</code> will be unable to copy the associated + * pixels. The area that is omitted can be refreshed by calling + * the component's <code>paint</code> method. + * + * @param x the <i>x</i> coordinate of the source rectangle. + * @param y the <i>y</i> coordinate of the source rectangle. + * @param width the width of the source rectangle. + * @param height the height of the source rectangle. + * @param dx the horizontal distance to copy the pixels. + * @param dy the vertical distance to copy the pixels. + */ + public void copyArea(final int x, final int y, final int width, final int height, + final int dx, final int dy) { + //source area + Rectangle sr = new Rectangle(x, y, width, height); + _transform(sr); + if (clip != null) + sr = clip.intersection(sr); + + //destination area + Rectangle dr = new Rectangle(x + dx, y + dy, width, height); + _transform(dr); + if (clip != null) + dr = clip.intersection(dr); + + final int w = Math.min(sr.width, dr.width); + final int h = Math.min(sr.height, dr.height); + + if (dr.x != sr.x + dx) sr.x = dr.x - dx; + if (dr.y != sr.y + dy) sr.y = dr.y - dy; + + + surface.copyArea(sr.x, sr.y, w, h, dx, dy); + } + + /** + * Draws the outline of a circular or elliptical arc + * covering the specified rectangle. + * <p/> + * The resulting arc begins at <code>startAngle</code> and extends + * for <code>arcAngle</code> degrees, using the current color. + * Angles are interpreted such that 0 degrees + * is at the 3 o'clock position. + * A positive value indicates a counter-clockwise rotation + * while a negative value indicates a clockwise rotation. + * <p/> + * The center of the arc is the center of the rectangle whose origin + * is (<i>x</i>, <i>y</i>) and whose size is specified by the + * <code>width</code> and <code>height</code> arguments. + * <p/> + * The resulting arc covers an area + * <code>width + 1</code> pixels wide + * by <code>height + 1</code> pixels tall. + * <p/> + * The angles are specified relative to the non-square extents of + * the bounding rectangle such that 45 degrees always falls on the + * line from the center of the ellipse to the upper right corner of + * the bounding rectangle. As a result, if the bounding rectangle is + * noticeably longer in one axis than the other, the angles to the + * start and end of the arc segment will be skewed farther along the + * longer axis of the bounds. + * + * @param x the <i>x</i> coordinate of the + * upper-left corner of the arc to be drawn. + * @param y the <i>y</i> coordinate of the + * upper-left corner of the arc to be drawn. + * @param width the width of the arc to be drawn. + * @param height the height of the arc to be drawn. + * @param startAngle the beginning angle. + * @param arcAngle the angular extent of the arc, + * relative to the start angle. + * @see java.awt.Graphics#fillArc + */ + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + //todo implement it + org.jnode.vm.Unsafe.debug("SimpleSurfaceGraphics.drawArc() not implemented\n"); + } + + /** + * Draws as much of the specified area of the specified image as is + * currently available, scaling it on the fly to fit inside the + * specified area of the destination drawable surface. Transparent pixels + * do not affect whatever pixels are already there. + * <p/> + * This method returns immediately in all cases, even if the + * image area to be drawn has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete then + * <code>drawImage</code> returns <code>false</code>. As more of + * the image becomes available, the process that loads the image notifies + * the specified image observer. + * <p/> + * This method always uses the unscaled version of the image + * to render the scaled rectangle and performs the required + * scaling on the fly. It does not use a cached, scaled version + * of the image for this operation. Scaling of the image from source + * to destination is performed such that the first coordinate + * of the source rectangle is mapped to the first coordinate of + * the destination rectangle, and the second source coordinate is + * mapped to the second destination coordinate. The subimage is + * scaled and flipped as needed to preserve those mappings. + * + * @param img the specified image to be drawn. This method does + * nothing if <code>img</code> is null. + * @param dx1 the <i>x</i> coordinate of the first corner of the + * destination rectangle. + * @param dy1 the <i>y</i> coordinate of the first corner of the + * destination rectangle. + * @param dx2 the <i>x</i> coordinate of the second corner of the + * destination rectangle. + * @param dy2 the <i>y</i> coordinate of the second corner of the + * destination rectangle. + * @param sx1 the <i>x</i> coordinate of the first corner of the + * source rectangle. + * @param sy1 the <i>y</i> coordinate of the first corner of the + * source rectangle. + * @param sx2 the <i>x</i> coordinate of the second corner of the + * source rectangle. + * @param sy2 the <i>y</i> coordinate of the second corner of the + * source rectangle. + * @param observer object to be notified as more of the image is + * scaled and converted. + * @return <code>false</code> if the image pixels are still changing; + * <code>true</code> otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + * @since JDK1.1 + */ + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) { + + return img == null || drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); + } + + /** + * Draws as much of the specified area of the specified image as is + * currently available, scaling it on the fly to fit inside the + * specified area of the destination drawable surface. + * <p/> + * Transparent pixels are drawn in the specified background color. + * This operation is equivalent to filling a rectangle of the + * width and height of the specified image with the given color and then + * drawing the image on top of it, but possibly more efficient. + * <p/> + * This method returns immediately in all cases, even if the + * image area to be drawn has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete then + * <code>drawImage</code> returns <code>false</code>. As more of + * the image becomes available, the process that loads the image notifies + * the specified image observer. + * <p/> + * This method always uses the unscaled version of the image + * to render the scaled rectangle and performs the required + * scaling on the fly. It does not use a cached, scaled version + * of the image for this operation. Scaling of the image from source + * to destination is performed such that the first coordinate + * of the source rectangle is mapped to the first coordinate of + * the destination rectangle, and the second source coordinate is + * mapped to the second destination coordinate. The subimage is + * scaled and flipped as needed to preserve those mappings. + * + * @param img the specified image to be drawn. This method does + * nothing if <code>img</code> is null. + * @param dx1 the <i>x</i> coordinate of the first corner of the + * destination rectangle. + * @param dy1 the <i>y</i> coordinate of the first corner of the + * destination rectangle. + * @param dx2 the <i>x</i> coordinate of the second corner of the + * destination rectangle. + * @param dy2 the <i>y</i> coordinate of the second corner of the + * destination rectangle. + * @param sx1 the <i>x</i> coordinate of the first corner of the + * source rectangle. + * @param sy1 the <i>y</i> coordinate of the first corner of the + * source rectangle. + * @param sx2 the <i>x</i> coordinate of the second corner of the + * source rectangle. + * @param sy2 the <i>y</i> coordinate of the second corner of the + * source rectangle. + * @param bgcolor the background color to paint under the + * non-opaque portions of the image. + * @param observer object to be notified as more of the image is + * scaled and converted. + * @return <code>false</code> if the image pixels are still changing; + * <code>true</code> otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + * @since JDK1.1 + */ + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) { + if (img == null) return true; + + if (dx1 == dx2 || dy1 == dy2) { + return true; + } + if (sx1 == sx2 || sy1 == sy2) { + return true; + } + + final int widthImage; + final int heightImage; + final int xImage; + final int yImage; + if (sx2 > sx1) { + widthImage = sx2 - sx1 + 1; + xImage = sx1; + } else { + widthImage = sx1 - sx2 + 1; + xImage = sx2; + } + + if (sy2 > sy1) { + heightImage = sy2 - sy1 + 1; + yImage = sy1; + } else { + heightImage = sy1 - sy2 + 1; + yImage = sy2; + } + + final int widthDest; + final int heightDest; + final int xDest; + final int yDest; + if (dx2 > dx1) { + widthDest = dx2 - dx1 + 1; + xDest = dx1; + } else { + widthDest = dx1 - dx2 + 1; + xDest = dx2; + } + + if (dy2 > dy1) { + heightDest = dy2 - dy1 + 1; + yDest = dy1; + } else { + heightDest = dy1 - dy2 + 1; + yDest = dy2; + } + + // Extract the image with a CropImageFilter + final Image imageArea = new ToolkitImage(new FilteredImageSource(img.getSource(), + new CropImageFilter(xImage, yImage, widthImage, heightImage))); + + if (bgcolor == null) { + return drawImage(imageArea, xDest, yDest, widthDest, heightDest, observer); + } else { + return drawImage(imageArea, xDest, yDest, widthDest, heightDest, bgcolor, observer); + } + } + + /** + * Draws as much of the specified image as is currently available. + * The image is drawn with its top-left corner at + * (<i>x</i>, <i>y</i>) in this graphics context's coordinate + * space. Transparent pixels are drawn in the specified + * background color. + * <p/> + * This operation is equivalent to filling a rectangle of the + * width and height of the specified image with the given color and then + * drawing the image on top of it, but possibly more efficient. + * <p/> + * This method returns immediately in all cases, even if the + * complete image has not yet been loaded, and it has not been dithered + * and converted for the current output device. + * <p/> + * If the image has completely loaded and its pixels are + * no longer being changed, then + * <code>drawImage</code> returns <code>true</code>. + * Otherwise, <code>drawImage</code> returns <code>false</code> + * and as more of + * the image becomes available + * or it is time to draw another frame of animation, + * the process that loads the image notifies + * the specified image observer. + * + * @param img the specified image to be drawn. This method does + * nothing if <code>img</code> is null. + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + * @param bgcolor the background color to paint under the + * non-opaque portions of the image. + * @param observer object to be notified as more of + * the image is converted. + * @return <code>false</code> if the image pixels are still changing; + * <code>true</code> otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + if (img == null) return true; + try { + Raster rast = getCompatibleRaster(img); + Rectangle r = new Rectangle(x, y, rast.getWidth(), rast.getHeight()); + _transform(r); + if (clip != null) + r = clip.intersection(r); + + surface.drawCompatibleRaster(rast, 0, 0, r.x, r.y, r.width, r.height, bgcolor); + surface.update(r.x, r.y, r.width + 2, r.height + 2); + return true; + } catch (InterruptedException ie) { + return false; + } + } + + /** + * Draws as much of the specified image as is currently available. + * The image is drawn with its top-left corner at + * (<i>x</i>, <i>y</i>) in this graphics context's coordinate + * space. Transparent pixels in the image do not affect whatever + * pixels are already there. + * <p/> + * This method returns immediately in all cases, even if the + * complete image has not yet been loaded, and it has not been dithered + * and converted for the current output device. + * <p/> + * If the image has completely loaded and its pixels are + * no longer being changed, then + * <code>drawImage</code> returns <code>true</code>. + * Otherwise, <code>drawImage</code> returns <code>false</code> + * and as more of + * the image becomes available + * or it is time to draw another frame of animation, + * the process that loads the image notifies + * the specified image observer. + * + * @param img the specified image to be drawn. This method does + * nothing if <code>img</code> is null. + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + * @param observer object to be notified as more of + * the image is converted. + * @return <code>false</code> if the image pixels are still changing; + * <code>true</code> otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + if (img == null) return true; + try { + Raster rast = getCompatibleRaster(img); + Rectangle r = new Rectangle(x, y, rast.getWidth(), rast.getHeight()); + _transform(r); + if (clip != null) + r = clip.intersection(r); + + surface.drawCompatibleRaster(rast, 0, 0, r.x, r.y, r.width, r.height, null); + surface.update(r.x, r.y, r.width + 2, r.height + 2); + return true; + } catch (InterruptedException ie) { + return false; + } + } + + /** + * Draws as much of the specified image as has already been scaled + * to fit inside the specified rectangle. + * <p/> + * The image is drawn inside the specified rectangle of this + * graphics context's coordinate space, and is scaled if + * necessary. Transparent pixels are drawn in the specified + * background color. + * This operation is equivalent to filling a rectangle of the + * width and height of the specified image with the given color and then + * drawing the image on top of it, but possibly more efficient. + * <p/> + * This method returns immediately in all cases, even if the + * entire image has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete then + * <code>drawImage</code> returns <code>false</code>. As more of + * the image becomes available, the process that loads the image notifies + * the specified image observer. + * <p/> + * A scaled version of an image will not necessarily be + * available immediately just because an unscaled version of the + * image has been constructed for this output device. Each size of + * the image may be cached separately and generated from the original + * data in a separate image production sequence. + * + * @param img the specified image to be drawn. This method does + * nothing if <code>img</code> is null. + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + * @param width the width of the rectangle. + * @param height the height of the rectangle. + * @param bgcolor the background color to paint under the + * non-opaque portions of the image. + * @param observer object to be notified as more of + * the image is converted. + * @return <code>false</code> if the image pixels are still changing; + * <code>true</code> otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + return img == null || drawImage(new ToolkitImage(new FilteredImageSource(img.getSource(), + new AreaAveragingScaleFilter(width, height))), x, y, bgcolor, observer); + } + + /** + * Draws as much of the specified image as has already been scaled + * to fit inside the specified rectangle. + * <p/> + * The image is drawn inside the specified rectangle of this + * graphics context's coordinate space, and is scaled if + * necessary. Transparent pixels do not affect whatever pixels + * are already there. + * <p/> + * This method returns immediately in all cases, even if the + * entire image has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete, then + * <code>drawImage</code> returns <code>false</code>. As more of + * the image becomes available, the process that loads the image notifies + * the image observer by calling its <code>imageUpdate</code> method. + * <p/> + * A scaled version of an image will not necessarily be + * available immediately just because an unscaled version of the + * image has been constructed for this output device. Each size of + * the image may be cached separately and generated from the original + * data in a separate image production sequence. + * + * @param img the specified image to be drawn. This method does + * nothing if <code>img</code> is null. + * @param x the <i>x</i> coordinate. + * @param y the <i>y</i> coordinate. + * @param width the width of the rectangle. + * @param height the height of the rectangle. + * @param observer object to be notified as more of + * the image is converted. + * @return <code>false</code> if the image pixels are still changing; + * <code>true</code> otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + return img == null || drawImage(new ToolkitImage(new FilteredImageSource(img.getSource(), + new AreaAveragingScaleFilter(width, height))), x, y, observer); + } + + /** + * Draws a line, using the current color, between the points + * <code>(x1, y1)</code> and <code>(x2, y2)</code> + * in this graphics context's coordinate system. + * + * @param x1 the first point's <i>x</i> coordinate. + * @param y1 the first point's <i>y</i> coordinate. + * @param x2 the second point's <i>x</i> coordinate. + * @param y2 the second point's <i>y</i> coordinate. + */ + public void drawLine(int x1, int y1, int x2, int y2) { + x1 += origin.x; + y1 += origin.y; + x2 += origin.x; + y2 += origin.y; + + if (clip == null || (clip.contains(x1, y1) && clip.contains(x2, y2))) { + surface.drawLine(x1, y1, x2, y2, color.getRGB(), mode); + } else { + //todo optimize clipping + //copute clipped line coordinates with the Liang-Barsjky alogorithm + drawLineClipped(x1, x2, y1, y2); + } + + if (x1 == x2) { + if (y1 == y2) + surface.update(x1, y1, 2, 2); + else if (y1 < y2) + surface.update(x1, y1, 2, y2 - y1 + 2); + else + surface.update(x1, y2, 2, y1 - y2 + 2); + + } else if (y1 == y2) { + if (x1 < x2) + surface.update(x1, y1, x2 - x1 + 2, 2); + else + surface.update(x2, y1, x1 - x2 + 2, 2); + } else { + if (x1 < x2 && y1 < y2) + surface.update(x1, y1, x2 - x1 + 2, y2 - y1 + 2); + else if (x1 < x2 && y1 > y2) + surface.update(x1, y2, x2 - x1 + 2, y1 - y2 + 2); + else if (x1 > x2 && y1 < y2) + surface.update(x2, y1, x1 - x2 + 2, y2 - y1 + 2); + else if (x1 > x2 && y1 > y2) + surface.update(x2, y2, x1 - x2 + 2, y1 - y2 + 2); + } + } + + private void drawLineClipped(int x1, int x2, int y1, int y2) { + final int incx, incy; + int countx, county; + + final int sizex = Math.abs(x2 - x1); + final int sizey = Math.abs(y2 - y1); + if (x1 > x2) { + incx = -1; + } else { + incx = 1; + } + if (y1 > y2) { + incy = -1; + } else { + incy = 1; + } + countx = x1; + county = y1; + + drawPixelClipped(x1, y1); + if (sizex >= sizey) { + int y = sizex >> 1; + final int loops = sizex; + for (int i = 0; i < loops; i++) { + y += sizey; + if (y >= sizex) { + y -= sizex; + county += incy; + } + countx += incx; + drawPixelClipped(countx, county); + } + } else { + int x = sizey >> 1; + final int loops = sizey; + for (int i = 0; i < loops; i++) { + x += sizex; + if (x >= sizey) { + x -= sizey; + countx += incx; + } + county += incy; + drawPixelClipped(countx, county); + } + } + } + + private void drawPixelClipped(int x, int y) { + if (clip == null || clip.contains(x, y)) + surface.drawPixel(x, y,... [truncated message content] |