summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
diff options
context:
space:
mode:
authorAndrew Haley <aph@redhat.com>2016-09-30 16:24:48 +0000
committerAndrew Haley <aph@gcc.gnu.org>2016-09-30 16:24:48 +0000
commit07b78716af6a9d7c9fd1e94d9baf94a52c873947 (patch)
tree3f22b3241c513ad168c8353805614ae1249410f4 /libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
parenteae993948bae8b788c53772bcb9217c063716f93 (diff)
Makefile.def: Remove libjava.
2016-09-30 Andrew Haley <aph@redhat.com> * Makefile.def: Remove libjava. * Makefile.tpl: Likewise. * Makefile.in: Regenerate. * configure.ac: Likewise. * configure: Likewise. * gcc/java: Remove. * libjava: Likewise. From-SVN: r240662
Diffstat (limited to 'libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java')
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java2094
1 files changed, 0 insertions, 2094 deletions
diff --git a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
deleted file mode 100644
index 1334866f270..00000000000
--- a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java
+++ /dev/null
@@ -1,2094 +0,0 @@
-/* AbstractGraphics2D.java -- Abstract Graphics2D implementation
- Copyright (C) 2006 Free Software Foundation, Inc.
-
-This file is part of GNU Classpath.
-
-GNU Classpath is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU Classpath is distributed in the hope that it will be useful, but
-WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301 USA.
-
-Linking this library statically or dynamically with other modules is
-making a combined work based on this library. Thus, the terms and
-conditions of the GNU General Public License cover the whole
-combination.
-
-As a special exception, the copyright holders of this library give you
-permission to link this library with independent modules to produce an
-executable, regardless of the license terms of these independent
-modules, and to copy and distribute the resulting executable under
-terms of your choice, provided that you also meet, for each linked
-independent module, the terms and conditions of the license of that
-module. An independent module is a module which is not derived from
-or based on this library. If you modify this library, you may extend
-this exception to your version of the library, but you are not
-obligated to do so. If you do not wish to do so, delete this
-exception statement from your version. */
-
-package gnu.java.awt.java2d;
-
-import gnu.java.util.LRUCache;
-
-import java.awt.AWTError;
-import java.awt.AlphaComposite;
-import java.awt.AWTPermission;
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.CompositeContext;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.PaintContext;
-import java.awt.Point;
-import java.awt.Polygon;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.Toolkit;
-import java.awt.RenderingHints.Key;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.Area;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Line2D;
-import java.awt.geom.NoninvertibleTransformException;
-import java.awt.geom.RoundRectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.FilteredImageSource;
-import java.awt.image.ImageObserver;
-import java.awt.image.ImageProducer;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.awt.image.ReplicateScaleFilter;
-import java.awt.image.SampleModel;
-import java.awt.image.WritableRaster;
-import java.awt.image.renderable.RenderableImage;
-import java.text.AttributedCharacterIterator;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-/**
- * This is a 100% Java implementation of the Java2D rendering pipeline. It is
- * meant as a base class for Graphics2D implementations.
- *
- * <h2>Backend interface</h2>
- * <p>
- * The backend must at the very least provide a Raster which the the rendering
- * pipeline can paint into. This must be implemented in
- * {@link #getDestinationRaster()}. For some backends that might be enough, like
- * when the target surface can be directly access via the raster (like in
- * BufferedImages). Other targets need some way to synchronize the raster with
- * the surface, which can be achieved by implementing the
- * {@link #updateRaster(Raster, int, int, int, int)} method, which always gets
- * called after a chunk of data got painted into the raster.
- * </p>
- * <p>Alternativly the backend can provide a method for filling Shapes by
- * overriding the protected method fillShape(). This can be accomplished
- * by a polygon filling function of the backend. Keep in mind though that
- * Shapes can be quite complex (i.e. non-convex and containing holes, etc)
- * which is not supported by all polygon fillers. Also it must be noted
- * that fillShape() is expected to handle painting and compositing as well as
- * clipping and transformation. If your backend can't support this natively,
- * then you can fallback to the implementation in this class. You'll need
- * to provide a writable Raster then, see above.</p>
- * <p>Another alternative is to implement fillScanline() which only requires
- * the backend to be able to draw horizontal lines in device space,
- * which is usually very cheap.
- * The implementation should still handle painting and compositing,
- * but no more clipping and transformation is required by the backend.</p>
- * <p>The backend is free to provide implementations for the various raw*
- * methods for optimized AWT 1.1 style painting of some primitives. This should
- * accelerate painting of Swing greatly. When doing so, the backend must also
- * keep track of the clip and translation, probably by overriding
- * some clip and translate methods. Don't forget to message super in such a
- * case.</p>
- *
- * <h2>Acceleration options</h2>
- * <p>
- * The fact that it is
- * pure Java makes it a little slow. However, there are several ways of
- * accelerating the rendering pipeline:
- * <ol>
- * <li><em>Optimization hooks for AWT 1.1 - like graphics operations.</em>
- * The most important methods from the {@link java.awt.Graphics} class
- * have a corresponding <code>raw*</code> method, which get called when
- * several optimization conditions are fullfilled. These conditions are
- * described below. Subclasses can override these methods and delegate
- * it directly to a native backend.</li>
- * <li><em>Native PaintContexts and CompositeContext.</em> The implementations
- * for the 3 PaintContexts and AlphaCompositeContext can be accelerated
- * using native code. These have proved to two of the most performance
- * critical points in the rendering pipeline and cannot really be done quickly
- * in plain Java because they involve lots of shuffling around with large
- * arrays. In fact, you really would want to let the graphics card to the
- * work, they are made for this.</li>
- * <li>Provide an accelerated implementation for fillShape(). For instance,
- * OpenGL can fill shapes very efficiently. There are some considerations
- * to be made though, see above for details.</li>
- * </ol>
- * </p>
- *
- * @author Roman Kennke (kennke@aicas.com)
- */
-public abstract class AbstractGraphics2D
- extends Graphics2D
- implements Cloneable, Pixelizer
-{
- /**
- * Caches scaled versions of an image.
- *
- * @see #drawImage(Image, int, int, int, int, ImageObserver)
- */
- protected static final WeakHashMap<Image, HashMap<Dimension,Image>> imageCache =
- new WeakHashMap<Image, HashMap<Dimension, Image>>();
-
- /**
- * Wether we use anti aliasing for rendering text by default or not.
- */
- private static final boolean DEFAULT_TEXT_AA =
- Boolean.getBoolean("gnu.java2d.default_text_aa");
-
- /**
- * The default font to use on the graphics object.
- */
- private static final Font FONT = new Font("SansSerif", Font.PLAIN, 12);
-
- /**
- * The size of the LRU cache used for caching GlyphVectors.
- */
- private static final int GV_CACHE_SIZE = 50;
-
- /**
- * Caches certain shapes to avoid massive creation of such Shapes in
- * the various draw* and fill* methods.
- */
- private static final ShapeCache shapeCache = new ShapeCache();
-
- /**
- * A pool of scanline converters. It is important to reuse scanline
- * converters because they keep their datastructures in place. We pool them
- * for use in multiple threads.
- */
- private static final LinkedList<ScanlineConverter> scanlineConverters =
- new LinkedList<ScanlineConverter>();
-
- /**
- * Caches glyph vectors for better drawing performance.
- */
- private static final Map<TextCacheKey,GlyphVector> gvCache =
- Collections.synchronizedMap(new LRUCache<TextCacheKey,GlyphVector>(GV_CACHE_SIZE));
-
- /**
- * This key is used to search in the gvCache without allocating a new
- * key each time.
- */
- private static final TextCacheKey searchTextKey = new TextCacheKey();
-
- /**
- * The transformation for this Graphics2D instance
- */
- protected AffineTransform transform;
-
- /**
- * The foreground.
- */
- private Paint paint;
-
- /**
- * The paint context during rendering.
- */
- private PaintContext paintContext = null;
-
- /**
- * The background.
- */
- private Color background = Color.WHITE;
-
- /**
- * Foreground color, as set by setColor.
- */
- private Color foreground = Color.BLACK;
- private boolean isForegroundColorNull = true;
-
- /**
- * The current font.
- */
- private Font font;
-
- /**
- * The current composite setting.
- */
- private Composite composite;
-
- /**
- * The current stroke setting.
- */
- private Stroke stroke;
-
- /**
- * The current clip. This clip is in user coordinate space.
- */
- private Shape clip;
-
- /**
- * The rendering hints.
- */
- private RenderingHints renderingHints;
-
- /**
- * The raster of the destination surface. This is where the painting is
- * performed.
- */
- private WritableRaster destinationRaster;
-
- /**
- * Indicates if certain graphics primitives can be rendered in an optimized
- * fashion. This will be the case if the following conditions are met:
- * - The transform may only be a translation, no rotation, shearing or
- * scaling.
- * - The paint must be a solid color.
- * - The composite must be an AlphaComposite.SrcOver.
- * - The clip must be a Rectangle.
- * - The stroke must be a plain BasicStroke().
- *
- * These conditions represent the standard settings of a new
- * AbstractGraphics2D object and will be the most commonly used setting
- * in Swing rendering and should therefore be optimized as much as possible.
- */
- private boolean isOptimized = true;
-
- private static final BasicStroke STANDARD_STROKE = new BasicStroke();
-
- private static final HashMap<Key, Object> STANDARD_HINTS;
- static
- {
-
- HashMap<Key, Object> hints = new HashMap<Key, Object>();
- hints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
- RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
- hints.put(RenderingHints.KEY_ANTIALIASING,
- RenderingHints.VALUE_ANTIALIAS_DEFAULT);
-
- STANDARD_HINTS = hints;
- }
-
- /**
- * Creates a new AbstractGraphics2D instance.
- */
- protected AbstractGraphics2D()
- {
- transform = new AffineTransform();
- background = Color.WHITE;
- composite = AlphaComposite.SrcOver;
- stroke = STANDARD_STROKE;
- renderingHints = new RenderingHints(STANDARD_HINTS);
- }
-
- /**
- * Draws the specified shape. The shape is passed through the current stroke
- * and is then forwarded to {@link #fillShape}.
- *
- * @param shape the shape to draw
- */
- public void draw(Shape shape)
- {
- // Stroke the shape.
- Shape strokedShape = stroke.createStrokedShape(shape);
- // Fill the stroked shape.
- fillShape(strokedShape, false);
- }
-
-
- /**
- * Draws the specified image and apply the transform for image space ->
- * user space conversion.
- *
- * This method is implemented to special case RenderableImages and
- * RenderedImages and delegate to
- * {@link #drawRenderableImage(RenderableImage, AffineTransform)} and
- * {@link #drawRenderedImage(RenderedImage, AffineTransform)} accordingly.
- * Other image types are not yet handled.
- *
- * @param image the image to be rendered
- * @param xform the transform from image space to user space
- * @param obs the image observer to be notified
- */
- public boolean drawImage(Image image, AffineTransform xform,
- ImageObserver obs)
- {
- Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs),
- image.getHeight(obs));
- return drawImageImpl(image, xform, obs, areaOfInterest);
- }
-
- /**
- * Draws the specified image and apply the transform for image space ->
- * user space conversion. This method only draw the part of the image
- * specified by <code>areaOfInterest</code>.
- *
- * This method is implemented to special case RenderableImages and
- * RenderedImages and delegate to
- * {@link #drawRenderableImage(RenderableImage, AffineTransform)} and
- * {@link #drawRenderedImage(RenderedImage, AffineTransform)} accordingly.
- * Other image types are not yet handled.
- *
- * @param image the image to be rendered
- * @param xform the transform from image space to user space
- * @param obs the image observer to be notified
- * @param areaOfInterest the area in image space that is rendered
- */
- private boolean drawImageImpl(Image image, AffineTransform xform,
- ImageObserver obs, Rectangle areaOfInterest)
- {
- boolean ret;
- if (image == null)
- {
- ret = true;
- }
- else if (image instanceof RenderedImage)
- {
- // FIXME: Handle the ImageObserver.
- drawRenderedImageImpl((RenderedImage) image, xform, areaOfInterest);
- ret = true;
- }
- else if (image instanceof RenderableImage)
- {
- // FIXME: Handle the ImageObserver.
- drawRenderableImageImpl((RenderableImage) image, xform, areaOfInterest);
- ret = true;
- }
- else
- {
- // FIXME: Implement rendering of other Image types.
- ret = false;
- }
- return ret;
- }
-
- /**
- * Renders a BufferedImage and applies the specified BufferedImageOp before
- * to filter the BufferedImage somehow. The resulting BufferedImage is then
- * passed on to {@link #drawRenderedImage(RenderedImage, AffineTransform)}
- * to perform the final rendering.
- *
- * @param image the source buffered image
- * @param op the filter to apply to the buffered image before rendering
- * @param x the x coordinate to render the image to
- * @param y the y coordinate to render the image to
- */
- public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y)
- {
- BufferedImage filtered =
- op.createCompatibleDestImage(image, image.getColorModel());
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- drawRenderedImage(filtered, t);
- }
-
- /**
- * Renders the specified image to the destination raster. The specified
- * transform is used to convert the image into user space. The transform
- * of this AbstractGraphics2D object is used to transform from user space
- * to device space.
- *
- * The rendering is performed using the scanline algorithm that performs the
- * rendering of other shapes and a custom Paint implementation, that supplies
- * the pixel values of the rendered image.
- *
- * @param image the image to render to the destination raster
- * @param xform the transform from image space to user space
- */
- public void drawRenderedImage(RenderedImage image, AffineTransform xform)
- {
- Rectangle areaOfInterest = new Rectangle(image.getMinX(),
- image.getHeight(),
- image.getWidth(),
- image.getHeight());
- drawRenderedImageImpl(image, xform, areaOfInterest);
- }
-
- /**
- * Renders the specified image to the destination raster. The specified
- * transform is used to convert the image into user space. The transform
- * of this AbstractGraphics2D object is used to transform from user space
- * to device space. Only the area specified by <code>areaOfInterest</code>
- * is finally rendered to the target.
- *
- * The rendering is performed using the scanline algorithm that performs the
- * rendering of other shapes and a custom Paint implementation, that supplies
- * the pixel values of the rendered image.
- *
- * @param image the image to render to the destination raster
- * @param xform the transform from image space to user space
- */
- private void drawRenderedImageImpl(RenderedImage image,
- AffineTransform xform,
- Rectangle areaOfInterest)
- {
- // First we compute the transformation. This is made up of 3 parts:
- // 1. The areaOfInterest -> image space transform.
- // 2. The image space -> user space transform.
- // 3. The user space -> device space transform.
- AffineTransform t = new AffineTransform();
- t.translate(- areaOfInterest.x - image.getMinX(),
- - areaOfInterest.y - image.getMinY());
- t.concatenate(xform);
- t.concatenate(transform);
- AffineTransform it = null;
- try
- {
- it = t.createInverse();
- }
- catch (NoninvertibleTransformException ex)
- {
- // Ignore -- we return if the transform is not invertible.
- }
- if (it != null)
- {
- // Transform the area of interest into user space.
- GeneralPath aoi = new GeneralPath(areaOfInterest);
- aoi.transform(xform);
- // Render the shape using the standard renderer, but with a temporary
- // ImagePaint.
- ImagePaint p = new ImagePaint(image, it);
- Paint savedPaint = paint;
- try
- {
- paint = p;
- fillShape(aoi, false);
- }
- finally
- {
- paint = savedPaint;
- }
- }
- }
-
- /**
- * Renders a renderable image. This produces a RenderedImage, which is
- * then passed to {@link #drawRenderedImage(RenderedImage, AffineTransform)}
- * to perform the final rendering.
- *
- * @param image the renderable image to be rendered
- * @param xform the transform from image space to user space
- */
- public void drawRenderableImage(RenderableImage image, AffineTransform xform)
- {
- Rectangle areaOfInterest = new Rectangle((int) image.getMinX(),
- (int) image.getHeight(),
- (int) image.getWidth(),
- (int) image.getHeight());
- drawRenderableImageImpl(image, xform, areaOfInterest);
-
- }
-
- /**
- * Renders a renderable image. This produces a RenderedImage, which is
- * then passed to {@link #drawRenderedImage(RenderedImage, AffineTransform)}
- * to perform the final rendering. Only the area of the image specified
- * by <code>areaOfInterest</code> is rendered.
- *
- * @param image the renderable image to be rendered
- * @param xform the transform from image space to user space
- */
- private void drawRenderableImageImpl(RenderableImage image,
- AffineTransform xform,
- Rectangle areaOfInterest)
- {
- // TODO: Maybe make more clever usage of a RenderContext here.
- RenderedImage rendered = image.createDefaultRendering();
- drawRenderedImageImpl(rendered, xform, areaOfInterest);
- }
-
- /**
- * Draws the specified string at the specified location.
- *
- * @param text the string to draw
- * @param x the x location, relative to the bounding rectangle of the text
- * @param y the y location, relative to the bounding rectangle of the text
- */
- public void drawString(String text, int x, int y)
- {
- GlyphVector gv;
- synchronized (searchTextKey)
- {
- TextCacheKey tck = searchTextKey;
- FontRenderContext frc = getFontRenderContext();
- tck.setString(text);
- tck.setFont(font);
- tck.setFontRenderContext(frc);
- if (gvCache.containsKey(tck))
- {
- gv = gvCache.get(tck);
- }
- else
- {
- gv = font.createGlyphVector(frc, text.toCharArray());
- gvCache.put(new TextCacheKey(text, font, frc), gv);
- }
- }
- drawGlyphVector(gv, x, y);
- }
-
- /**
- * Draws the specified string at the specified location.
- *
- * @param text the string to draw
- * @param x the x location, relative to the bounding rectangle of the text
- * @param y the y location, relative to the bounding rectangle of the text
- */
- public void drawString(String text, float x, float y)
- {
- FontRenderContext ctx = getFontRenderContext();
- GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray());
- drawGlyphVector(gv, x, y);
- }
-
- /**
- * Draws the specified string (as AttributedCharacterIterator) at the
- * specified location.
- *
- * @param iterator the string to draw
- * @param x the x location, relative to the bounding rectangle of the text
- * @param y the y location, relative to the bounding rectangle of the text
- */
- public void drawString(AttributedCharacterIterator iterator, int x, int y)
- {
- FontRenderContext ctx = getFontRenderContext();
- GlyphVector gv = font.createGlyphVector(ctx, iterator);
- drawGlyphVector(gv, x, y);
- }
-
- /**
- * Draws the specified string (as AttributedCharacterIterator) at the
- * specified location.
- *
- * @param iterator the string to draw
- * @param x the x location, relative to the bounding rectangle of the text
- * @param y the y location, relative to the bounding rectangle of the text
- */
- public void drawString(AttributedCharacterIterator iterator, float x, float y)
- {
- FontRenderContext ctx = getFontRenderContext();
- GlyphVector gv = font.createGlyphVector(ctx, iterator);
- drawGlyphVector(gv, x, y);
- }
-
- /**
- * Fills the specified shape with the current foreground.
- *
- * @param shape the shape to fill
- */
- public void fill(Shape shape)
- {
- fillShape(shape, false);
- }
-
- public boolean hit(Rectangle rect, Shape text, boolean onStroke)
- {
- // FIXME: Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- /**
- * Sets the composite.
- *
- * @param comp the composite to set
- */
- public void setComposite(Composite comp)
- {
- if (! (comp instanceof AlphaComposite))
- {
- // FIXME: this check is only required "if this Graphics2D
- // context is drawing to a Component on the display screen".
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkPermission(new AWTPermission("readDisplayPixels"));
- }
-
- composite = comp;
- if (! (comp.equals(AlphaComposite.SrcOver)))
- isOptimized = false;
- else
- updateOptimization();
- }
-
- /**
- * Sets the current foreground.
- *
- * @param p the foreground to set.
- */
- public void setPaint(Paint p)
- {
- if (p != null)
- {
- paint = p;
-
- if (! (paint instanceof Color))
- {
- isOptimized = false;
- }
- else
- {
- this.foreground = (Color) paint;
- isForegroundColorNull = false;
- updateOptimization();
- }
- }
- else
- {
- this.foreground = Color.BLACK;
- isForegroundColorNull = true;
- }
-
- // free resources if needed, then put the paint context to null
- if (this.paintContext != null)
- this.paintContext.dispose();
-
- this.paintContext = null;
- }
-
- /**
- * Sets the stroke for this graphics object.
- *
- * @param s the stroke to set
- */
- public void setStroke(Stroke s)
- {
- stroke = s;
- if (! stroke.equals(new BasicStroke()))
- isOptimized = false;
- else
- updateOptimization();
- }
-
- /**
- * Sets the specified rendering hint.
- *
- * @param hintKey the key of the rendering hint
- * @param hintValue the value
- */
- public void setRenderingHint(Key hintKey, Object hintValue)
- {
- renderingHints.put(hintKey, hintValue);
- }
-
- /**
- * Returns the rendering hint for the specified key.
- *
- * @param hintKey the rendering hint key
- *
- * @return the rendering hint for the specified key
- */
- public Object getRenderingHint(Key hintKey)
- {
- return renderingHints.get(hintKey);
- }
-
- /**
- * Sets the specified rendering hints.
- *
- * @param hints the rendering hints to set
- */
- public void setRenderingHints(Map hints)
- {
- renderingHints.clear();
- renderingHints.putAll(hints);
- }
-
- /**
- * Adds the specified rendering hints.
- *
- * @param hints the rendering hints to add
- */
- public void addRenderingHints(Map hints)
- {
- renderingHints.putAll(hints);
- }
-
- /**
- * Returns the current rendering hints.
- *
- * @return the current rendering hints
- */
- public RenderingHints getRenderingHints()
- {
- return (RenderingHints) renderingHints.clone();
- }
-
- /**
- * Translates the coordinate system by (x, y).
- *
- * @param x the translation X coordinate
- * @param y the translation Y coordinate
- */
- public void translate(int x, int y)
- {
- transform.translate(x, y);
-
- // Update the clip. We special-case rectangular clips here, because they
- // are so common (e.g. in Swing).
- if (clip != null)
- {
- if (clip instanceof Rectangle)
- {
- Rectangle r = (Rectangle) clip;
- r.x -= x;
- r.y -= y;
- setClip(r);
- }
- else
- {
- AffineTransform clipTransform = new AffineTransform();
- clipTransform.translate(-x, -y);
- updateClip(clipTransform);
- }
- }
- }
-
- /**
- * Translates the coordinate system by (tx, ty).
- *
- * @param tx the translation X coordinate
- * @param ty the translation Y coordinate
- */
- public void translate(double tx, double ty)
- {
- transform.translate(tx, ty);
-
- // Update the clip. We special-case rectangular clips here, because they
- // are so common (e.g. in Swing).
- if (clip != null)
- {
- if (clip instanceof Rectangle)
- {
- Rectangle r = (Rectangle) clip;
- r.x -= tx;
- r.y -= ty;
- }
- else
- {
- AffineTransform clipTransform = new AffineTransform();
- clipTransform.translate(-tx, -ty);
- updateClip(clipTransform);
- }
- }
- }
-
- /**
- * Rotates the coordinate system by <code>theta</code> degrees.
- *
- * @param theta the angle be which to rotate the coordinate system
- */
- public void rotate(double theta)
- {
- transform.rotate(theta);
- if (clip != null)
- {
- AffineTransform clipTransform = new AffineTransform();
- clipTransform.rotate(-theta);
- updateClip(clipTransform);
- }
- updateOptimization();
- }
-
- /**
- * Rotates the coordinate system by <code>theta</code> around the point
- * (x, y).
- *
- * @param theta the angle by which to rotate the coordinate system
- * @param x the point around which to rotate, X coordinate
- * @param y the point around which to rotate, Y coordinate
- */
- public void rotate(double theta, double x, double y)
- {
- transform.rotate(theta, x, y);
- if (clip != null)
- {
- AffineTransform clipTransform = new AffineTransform();
- clipTransform.rotate(-theta, x, y);
- updateClip(clipTransform);
- }
- updateOptimization();
- }
-
- /**
- * Scales the coordinate system by the factors <code>scaleX</code> and
- * <code>scaleY</code>.
- *
- * @param scaleX the factor by which to scale the X axis
- * @param scaleY the factor by which to scale the Y axis
- */
- public void scale(double scaleX, double scaleY)
- {
- transform.scale(scaleX, scaleY);
- if (clip != null)
- {
- AffineTransform clipTransform = new AffineTransform();
- clipTransform.scale(1 / scaleX, 1 / scaleY);
- updateClip(clipTransform);
- }
- updateOptimization();
- }
-
- /**
- * Shears the coordinate system by <code>shearX</code> and
- * <code>shearY</code>.
- *
- * @param shearX the X shearing
- * @param shearY the Y shearing
- */
- public void shear(double shearX, double shearY)
- {
- transform.shear(shearX, shearY);
- if (clip != null)
- {
- AffineTransform clipTransform = new AffineTransform();
- clipTransform.shear(-shearX, -shearY);
- updateClip(clipTransform);
- }
- updateOptimization();
- }
-
- /**
- * Transforms the coordinate system using the specified transform
- * <code>t</code>.
- *
- * @param t the transform
- */
- public void transform(AffineTransform t)
- {
- transform.concatenate(t);
- try
- {
- AffineTransform clipTransform = t.createInverse();
- updateClip(clipTransform);
- }
- catch (NoninvertibleTransformException ex)
- {
- // TODO: How can we deal properly with this?
- ex.printStackTrace();
- }
- updateOptimization();
- }
-
- /**
- * Sets the transformation for this Graphics object.
- *
- * @param t the transformation to set
- */
- public void setTransform(AffineTransform t)
- {
- // Transform clip into target space using the old transform.
- updateClip(transform);
- transform.setTransform(t);
- // Transform the clip back into user space using the inverse new transform.
- try
- {
- updateClip(transform.createInverse());
- }
- catch (NoninvertibleTransformException ex)
- {
- // TODO: How can we deal properly with this?
- ex.printStackTrace();
- }
- updateOptimization();
- }
-
- /**
- * Returns the transformation of this coordinate system.
- *
- * @return the transformation of this coordinate system
- */
- public AffineTransform getTransform()
- {
- return (AffineTransform) transform.clone();
- }
-
- /**
- * Returns the current foreground.
- *
- * @return the current foreground
- */
- public Paint getPaint()
- {
- return paint;
- }
-
-
- /**
- * Returns the current composite.
- *
- * @return the current composite
- */
- public Composite getComposite()
- {
- return composite;
- }
-
- /**
- * Sets the current background.
- *
- * @param color the background to set.
- */
- public void setBackground(Color color)
- {
- background = color;
- }
-
- /**
- * Returns the current background.
- *
- * @return the current background
- */
- public Color getBackground()
- {
- return background;
- }
-
- /**
- * Returns the current stroke.
- *
- * @return the current stroke
- */
- public Stroke getStroke()
- {
- return stroke;
- }
-
- /**
- * Intersects the clip of this graphics object with the specified clip.
- *
- * @param s the clip with which the current clip should be intersected
- */
- public void clip(Shape s)
- {
- // Initialize clip if not already present.
- if (clip == null)
- setClip(s);
-
- // This is so common, let's optimize this.
- else if (clip instanceof Rectangle && s instanceof Rectangle)
- {
- Rectangle clipRect = (Rectangle) clip;
- Rectangle r = (Rectangle) s;
- computeIntersection(r.x, r.y, r.width, r.height, clipRect);
- // Call setClip so that subclasses get notified.
- setClip(clipRect);
- }
- else
- {
- Area current;
- if (clip instanceof Area)
- current = (Area) clip;
- else
- current = new Area(clip);
-
- Area intersect;
- if (s instanceof Area)
- intersect = (Area) s;
- else
- intersect = new Area(s);
-
- current.intersect(intersect);
- clip = current;
- isOptimized = false;
- // Call setClip so that subclasses get notified.
- setClip(clip);
- }
- }
-
- public FontRenderContext getFontRenderContext()
- {
- // Protect our own transform from beeing modified.
- AffineTransform tf = new AffineTransform(transform);
- // TODO: Determine antialias and fractionalmetrics parameters correctly.
- return new FontRenderContext(tf, false, true);
- }
-
- /**
- * Draws the specified glyph vector at the specified location.
- *
- * @param gv the glyph vector to draw
- * @param x the location, x coordinate
- * @param y the location, y coordinate
- */
- public void drawGlyphVector(GlyphVector gv, float x, float y)
- {
- translate(x, y);
- fillShape(gv.getOutline(), true);
- translate(-x, -y);
- }
-
- /**
- * Creates a copy of this graphics object.
- *
- * @return a copy of this graphics object
- */
- public Graphics create()
- {
- AbstractGraphics2D copy = (AbstractGraphics2D) clone();
- return copy;
- }
-
- /**
- * Creates and returns a copy of this Graphics object. This should
- * be overridden by subclasses if additional state must be handled when
- * cloning. This is called by {@link #create()}.
- *
- * @return a copy of this Graphics object
- */
- protected Object clone()
- {
- try
- {
- AbstractGraphics2D copy = (AbstractGraphics2D) super.clone();
- // Copy the clip. If it's a Rectangle, preserve that for optimization.
- if (clip instanceof Rectangle)
- copy.clip = new Rectangle((Rectangle) clip);
- else if (clip != null)
- copy.clip = new GeneralPath(clip);
- else
- copy.clip = null;
-
- copy.renderingHints = new RenderingHints(null);
- copy.renderingHints.putAll(renderingHints);
- copy.transform = new AffineTransform(transform);
- // The remaining state is inmmutable and doesn't need to be copied.
- return copy;
- }
- catch (CloneNotSupportedException ex)
- {
- AWTError err = new AWTError("Unexpected exception while cloning");
- err.initCause(ex);
- throw err;
- }
- }
-
- /**
- * Returns the current foreground.
- */
- public Color getColor()
- {
- if (isForegroundColorNull)
- return null;
-
- return this.foreground;
- }
-
- /**
- * Sets the current foreground.
- *
- * @param color the foreground to set
- */
- public void setColor(Color color)
- {
- this.setPaint(color);
- }
-
- public void setPaintMode()
- {
- // FIXME: Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- public void setXORMode(Color color)
- {
- // FIXME: Implement this.
- throw new UnsupportedOperationException("Not yet implemented");
- }
-
- /**
- * Returns the current font.
- *
- * @return the current font
- */
- public Font getFont()
- {
- return font;
- }
-
- /**
- * Sets the font on this graphics object. When <code>f == null</code>, the
- * current setting is not changed.
- *
- * @param f the font to set
- */
- public void setFont(Font f)
- {
- if (f != null)
- font = f;
- }
-
- /**
- * Returns the font metrics for the specified font.
- *
- * @param font the font for which to fetch the font metrics
- *
- * @return the font metrics for the specified font
- */
- public FontMetrics getFontMetrics(Font font)
- {
- return Toolkit.getDefaultToolkit().getFontMetrics(font);
- }
-
- /**
- * Returns the bounds of the current clip.
- *
- * @return the bounds of the current clip
- */
- public Rectangle getClipBounds()
- {
- Rectangle b = null;
- if (clip != null)
- b = clip.getBounds();
- return b;
- }
-
- /**
- * Intersects the current clipping region with the specified rectangle.
- *
- * @param x the x coordinate of the rectangle
- * @param y the y coordinate of the rectangle
- * @param width the width of the rectangle
- * @param height the height of the rectangle
- */
- public void clipRect(int x, int y, int width, int height)
- {
- clip(new Rectangle(x, y, width, height));
- }
-
- /**
- * Sets the clip to the specified rectangle.
- *
- * @param x the x coordinate of the clip rectangle
- * @param y the y coordinate of the clip rectangle
- * @param width the width of the clip rectangle
- * @param height the height of the clip rectangle
- */
- public void setClip(int x, int y, int width, int height)
- {
- setClip(new Rectangle(x, y, width, height));
- }
-
- /**
- * Returns the current clip.
- *
- * @return the current clip
- */
- public Shape getClip()
- {
- return clip;
- }
-
- /**
- * Sets the current clipping area to <code>clip</code>.
- *
- * @param c the clip to set
- */
- public void setClip(Shape c)
- {
- clip = c;
- if (! (clip instanceof Rectangle))
- isOptimized = false;
- else
- updateOptimization();
- }
-
- public void copyArea(int x, int y, int width, int height, int dx, int dy)
- {
- if (isOptimized)
- rawCopyArea(x, y, width, height, dx, dy);
- else
- copyAreaImpl(x, y, width, height, dx, dy);
- }
-
- /**
- * Draws a line from (x1, y1) to (x2, y2).
- *
- * This implementation transforms the coordinates and forwards the call to
- * {@link #rawDrawLine}.
- */
- public void drawLine(int x1, int y1, int x2, int y2)
- {
- if (isOptimized)
- {
- int tx = (int) transform.getTranslateX();
- int ty = (int) transform.getTranslateY();
- rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty);
- }
- else
- {
- ShapeCache sc = shapeCache;
- if (sc.line == null)
- sc.line = new Line2D.Float();
- sc.line.setLine(x1, y1, x2, y2);
- draw(sc.line);
- }
- }
-
- public void drawRect(int x, int y, int w, int h)
- {
- if (isOptimized)
- {
- int tx = (int) transform.getTranslateX();
- int ty = (int) transform.getTranslateY();
- rawDrawRect(x + tx, y + ty, w, h);
- }
- else
- {
- ShapeCache sc = shapeCache;
- if (sc.rect == null)
- sc.rect = new Rectangle();
- sc.rect.setBounds(x, y, w, h);
- draw(sc.rect);
- }
- }
-
- /**
- * Fills a rectangle with the current paint.
- *
- * @param x the upper left corner, X coordinate
- * @param y the upper left corner, Y coordinate
- * @param width the width of the rectangle
- * @param height the height of the rectangle
- */
- public void fillRect(int x, int y, int width, int height)
- {
- if (isOptimized)
- {
- rawFillRect(x + (int) transform.getTranslateX(),
- y + (int) transform.getTranslateY(), width, height);
- }
- else
- {
- ShapeCache sc = shapeCache;
- if (sc.rect == null)
- sc.rect = new Rectangle();
- sc.rect.setBounds(x, y, width, height);
- fill(sc.rect);
- }
- }
-
- /**
- * Fills a rectangle with the current background color.
- *
- * This implementation temporarily sets the foreground color to the
- * background and forwards the call to {@link #fillRect(int, int, int, int)}.
- *
- * @param x the upper left corner, X coordinate
- * @param y the upper left corner, Y coordinate
- * @param width the width of the rectangle
- * @param height the height of the rectangle
- */
- public void clearRect(int x, int y, int width, int height)
- {
- if (isOptimized)
- rawClearRect(x, y, width, height);
- else
- {
- Paint savedForeground = getPaint();
- setPaint(getBackground());
- fillRect(x, y, width, height);
- setPaint(savedForeground);
- }
- }
-
- /**
- * Draws a rounded rectangle.
- *
- * @param x the x coordinate of the rectangle
- * @param y the y coordinate of the rectangle
- * @param width the width of the rectangle
- * @param height the height of the rectangle
- * @param arcWidth the width of the arcs
- * @param arcHeight the height of the arcs
- */
- public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
- int arcHeight)
- {
- ShapeCache sc = shapeCache;
- if (sc.roundRect == null)
- sc.roundRect = new RoundRectangle2D.Float();
- sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
- draw(sc.roundRect);
- }
-
- /**
- * Fills a rounded rectangle.
- *
- * @param x the x coordinate of the rectangle
- * @param y the y coordinate of the rectangle
- * @param width the width of the rectangle
- * @param height the height of the rectangle
- * @param arcWidth the width of the arcs
- * @param arcHeight the height of the arcs
- */
- public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
- int arcHeight)
- {
- ShapeCache sc = shapeCache;
- if (sc.roundRect == null)
- sc.roundRect = new RoundRectangle2D.Float();
- sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight);
- fill(sc.roundRect);
- }
-
- /**
- * Draws the outline of an oval.
- *
- * @param x the upper left corner of the bounding rectangle of the ellipse
- * @param y the upper left corner of the bounding rectangle of the ellipse
- * @param width the width of the ellipse
- * @param height the height of the ellipse
- */
- public void drawOval(int x, int y, int width, int height)
- {
- ShapeCache sc = shapeCache;
- if (sc.ellipse == null)
- sc.ellipse = new Ellipse2D.Float();
- sc.ellipse.setFrame(x, y, width, height);
- draw(sc.ellipse);
- }
-
- /**
- * Fills an oval.
- *
- * @param x the upper left corner of the bounding rectangle of the ellipse
- * @param y the upper left corner of the bounding rectangle of the ellipse
- * @param width the width of the ellipse
- * @param height the height of the ellipse
- */
- public void fillOval(int x, int y, int width, int height)
- {
- ShapeCache sc = shapeCache;
- if (sc.ellipse == null)
- sc.ellipse = new Ellipse2D.Float();
- sc.ellipse.setFrame(x, y, width, height);
- fill(sc.ellipse);
- }
-
- /**
- * Draws an arc.
- */
- public void drawArc(int x, int y, int width, int height, int arcStart,
- int arcAngle)
- {
- ShapeCache sc = shapeCache;
- if (sc.arc == null)
- sc.arc = new Arc2D.Float();
- sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN);
- draw(sc.arc);
- }
-
- /**
- * Fills an arc.
- */
- public void fillArc(int x, int y, int width, int height, int arcStart,
- int arcAngle)
- {
- ShapeCache sc = shapeCache;
- if (sc.arc == null)
- sc.arc = new Arc2D.Float();
- sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE);
- draw(sc.arc);
- }
-
- public void drawPolyline(int[] xPoints, int[] yPoints, int npoints)
- {
- ShapeCache sc = shapeCache;
- if (sc.polyline == null)
- sc.polyline = new GeneralPath();
- GeneralPath p = sc.polyline;
- p.reset();
- if (npoints > 0)
- p.moveTo(xPoints[0], yPoints[0]);
- for (int i = 1; i < npoints; i++)
- p.lineTo(xPoints[i], yPoints[i]);
- fill(p);
- }
-
- /**
- * Draws the outline of a polygon.
- */
- public void drawPolygon(int[] xPoints, int[] yPoints, int npoints)
- {
- ShapeCache sc = shapeCache;
- if (sc.polygon == null)
- sc.polygon = new Polygon();
- sc.polygon.reset();
- sc.polygon.xpoints = xPoints;
- sc.polygon.ypoints = yPoints;
- sc.polygon.npoints = npoints;
- draw(sc.polygon);
- }
-
- /**
- * Fills the outline of a polygon.
- */
- public void fillPolygon(int[] xPoints, int[] yPoints, int npoints)
- {
- ShapeCache sc = shapeCache;
- if (sc.polygon == null)
- sc.polygon = new Polygon();
- sc.polygon.reset();
- sc.polygon.xpoints = xPoints;
- sc.polygon.ypoints = yPoints;
- sc.polygon.npoints = npoints;
- fill(sc.polygon);
- }
-
- /**
- * Draws the specified image at the specified location. This forwards
- * to {@link #drawImage(Image, AffineTransform, ImageObserver)}.
- *
- * @param image the image to render
- * @param x the x location to render to
- * @param y the y location to render to
- * @param observer the image observer to receive notification
- */
- public boolean drawImage(Image image, int x, int y, ImageObserver observer)
- {
- boolean ret;
- if (isOptimized)
- {
- ret = rawDrawImage(image, x + (int) transform.getTranslateX(),
- y + (int) transform.getTranslateY(), observer);
- }
- else
- {
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- ret = drawImage(image, t, observer);
- }
- return ret;
- }
-
- /**
- * Draws the specified image at the specified location. The image
- * is scaled to the specified width and height. This forwards
- * to {@link #drawImage(Image, AffineTransform, ImageObserver)}.
- *
- * @param image the image to render
- * @param x the x location to render to
- * @param y the y location to render to
- * @param width the target width of the image
- * @param height the target height of the image
- * @param observer the image observer to receive notification
- */
- public boolean drawImage(Image image, int x, int y, int width, int height,
- ImageObserver observer)
- {
- AffineTransform t = new AffineTransform();
- int imWidth = image.getWidth(observer);
- int imHeight = image.getHeight(observer);
- if (imWidth == width && imHeight == height)
- {
- // No need to scale, fall back to non-scaling loops.
- return drawImage(image, x, y, observer);
- }
- else
- {
- Image scaled = prepareImage(image, width, height);
- // Ideally, this should notify the observer about the scaling progress.
- return drawImage(scaled, x, y, observer);
- }
- }
-
- /**
- * Draws the specified image at the specified location. This forwards
- * to {@link #drawImage(Image, AffineTransform, ImageObserver)}.
- *
- * @param image the image to render
- * @param x the x location to render to
- * @param y the y location to render to
- * @param bgcolor the background color to use for transparent pixels
- * @param observer the image observer to receive notification
- */
- public boolean drawImage(Image image, int x, int y, Color bgcolor,
- ImageObserver observer)
- {
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- // TODO: Somehow implement the background option.
- return drawImage(image, t, observer);
- }
-
- /**
- * Draws the specified image at the specified location. The image
- * is scaled to the specified width and height. This forwards
- * to {@link #drawImage(Image, AffineTransform, ImageObserver)}.
- *
- * @param image the image to render
- * @param x the x location to render to
- * @param y the y location to render to
- * @param width the target width of the image
- * @param height the target height of the image
- * @param bgcolor the background color to use for transparent pixels
- * @param observer the image observer to receive notification
- */
- public boolean drawImage(Image image, int x, int y, int width, int height,
- Color bgcolor, ImageObserver observer)
- {
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- double scaleX = (double) image.getWidth(observer) / (double) width;
- double scaleY = (double) image.getHeight(observer) / (double) height;
- t.scale(scaleX, scaleY);
- // TODO: Somehow implement the background option.
- return drawImage(image, t, observer);
- }
-
- /**
- * Draws an image fragment to a rectangular area of the target.
- *
- * @param image the image to render
- * @param dx1 the first corner of the destination rectangle
- * @param dy1 the first corner of the destination rectangle
- * @param dx2 the second corner of the destination rectangle
- * @param dy2 the second corner of the destination rectangle
- * @param sx1 the first corner of the source rectangle
- * @param sy1 the first corner of the source rectangle
- * @param sx2 the second corner of the source rectangle
- * @param sy2 the second corner of the source rectangle
- * @param observer the image observer to be notified
- */
- public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
- int sx1, int sy1, int sx2, int sy2,
- ImageObserver observer)
- {
- int sx = Math.min(sx1, sx1);
- int sy = Math.min(sy1, sy2);
- int sw = Math.abs(sx1 - sx2);
- int sh = Math.abs(sy1 - sy2);
- int dx = Math.min(dx1, dx1);
- int dy = Math.min(dy1, dy2);
- int dw = Math.abs(dx1 - dx2);
- int dh = Math.abs(dy1 - dy2);
-
- AffineTransform t = new AffineTransform();
- t.translate(sx - dx, sy - dy);
- double scaleX = (double) sw / (double) dw;
- double scaleY = (double) sh / (double) dh;
- t.scale(scaleX, scaleY);
- Rectangle areaOfInterest = new Rectangle(sx, sy, sw, sh);
- return drawImageImpl(image, t, observer, areaOfInterest);
- }
-
- /**
- * Draws an image fragment to a rectangular area of the target.
- *
- * @param image the image to render
- * @param dx1 the first corner of the destination rectangle
- * @param dy1 the first corner of the destination rectangle
- * @param dx2 the second corner of the destination rectangle
- * @param dy2 the second corner of the destination rectangle
- * @param sx1 the first corner of the source rectangle
- * @param sy1 the first corner of the source rectangle
- * @param sx2 the second corner of the source rectangle
- * @param sy2 the second corner of the source rectangle
- * @param bgcolor the background color to use for transparent pixels
- * @param observer the image observer to be notified
- */
- public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2,
- int sx1, int sy1, int sx2, int sy2, Color bgcolor,
- ImageObserver observer)
- {
- // FIXME: Do something with bgcolor.
- return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
- }
-
- /**
- * Disposes this graphics object.
- */
- public void dispose()
- {
- // Nothing special to do here.
- }
-
- /**
- * Fills the specified shape. Override this if your backend can efficiently
- * fill shapes. This is possible on many systems via a polygon fill
- * method or something similar. But keep in mind that Shapes can be quite
- * complex (non-convex, with holes etc), which is not necessarily supported
- * by all polygon fillers. Also note that you must perform clipping
- * before filling the shape.
- *
- * @param s the shape to fill
- * @param isFont <code>true</code> if the shape is a font outline
- */
- protected void fillShape(Shape s, boolean isFont)
- {
- // Determine if we need to antialias stuff.
- boolean antialias = false;
- if (isFont)
- {
- Object v = renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING);
- // We default to antialiasing for text rendering.
- antialias = v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON
- || (v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT
- && DEFAULT_TEXT_AA);
- }
- else
- {
- Object v = renderingHints.get(RenderingHints.KEY_ANTIALIASING);
- antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON);
- }
- ScanlineConverter sc = getScanlineConverter();
- int resolution = 0;
- int yRes = 0;
- if (antialias)
- {
- // Adjust resolution according to rendering hints.
- resolution = 2;
- yRes = 4;
- }
- sc.renderShape(this, s, clip, transform, resolution, yRes, renderingHints);
- freeScanlineConverter(sc);
- }
-
- /**
- * Returns the color model of this Graphics object.
- *
- * @return the color model of this Graphics object
- */
- protected abstract ColorModel getColorModel();
-
- /**
- * Returns the bounds of the target.
- *
- * @return the bounds of the target
- */
- protected abstract Rectangle getDeviceBounds();
-
- /**
- * Draws a line in optimization mode. The implementation should respect the
- * clip and translation. It can assume that the clip is a rectangle and that
- * the transform is only a translating transform.
- *
- * @param x0 the starting point, X coordinate
- * @param y0 the starting point, Y coordinate
- * @param x1 the end point, X coordinate
- * @param y1 the end point, Y coordinate
- */
- protected void rawDrawLine(int x0, int y0, int x1, int y1)
- {
- ShapeCache sc = shapeCache;
- if (sc.line == null)
- sc.line = new Line2D.Float();
- sc.line.setLine(x0, y0, x1, y1);
- draw(sc.line);
- }
-
- protected void rawDrawRect(int x, int y, int w, int h)
- {
- ShapeCache sc = shapeCache;
- if (sc.rect == null)
- sc.rect = new Rectangle();
- sc.rect.setBounds(x, y, w, h);
- draw(sc.rect);
- }
-
- /**
- * Clears a rectangle in optimization mode. The implementation should respect the
- * clip and translation. It can assume that the clip is a rectangle and that
- * the transform is only a translating transform.
- *
- * @param x the upper left corner, X coordinate
- * @param y the upper left corner, Y coordinate
- * @param w the width
- * @param h the height
- */
- protected void rawClearRect(int x, int y, int w, int h)
- {
- Paint savedForeground = getPaint();
- setPaint(getBackground());
- rawFillRect(x, y, w, h);
- setPaint(savedForeground);
- }
-
- /**
- * Fills a rectangle in optimization mode. The implementation should respect
- * the clip but can assume that it is a rectangle.
- *
- * @param x the upper left corner, X coordinate
- * @param y the upper left corner, Y coordinate
- * @param w the width
- * @param h the height
- */
- protected void rawFillRect(int x, int y, int w, int h)
- {
- ShapeCache sc = shapeCache;
- if (sc.rect == null)
- sc.rect = new Rectangle();
- sc.rect.setBounds(x, y, w, h);
- fill(sc.rect);
- }
-
- /**
- * Draws an image in optimization mode. The implementation should respect
- * the clip but can assume that it is a rectangle.
- *
- * @param image the image to be painted
- * @param x the location, X coordinate
- * @param y the location, Y coordinate
- * @param obs the image observer to be notified
- *
- * @return <code>true</code> when the image is painted completely,
- * <code>false</code> if it is still rendered
- */
- protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs)
- {
- AffineTransform t = new AffineTransform();
- t.translate(x, y);
- return drawImage(image, t, obs);
- }
-
- /**
- * Copies a rectangular region to another location.
- *
- * @param x the upper left corner, X coordinate
- * @param y the upper left corner, Y coordinate
- * @param w the width
- * @param h the height
- * @param dx
- * @param dy
- */
- protected void rawCopyArea(int x, int y, int w, int h, int dx, int dy)
- {
- copyAreaImpl(x, y, w, h, dx, dy);
- }
-
- // Private implementation methods.
-
- /**
- * Copies a rectangular area of the target raster to a different location.
- */
- private void copyAreaImpl(int x, int y, int w, int h, int dx, int dy)
- {
- // FIXME: Implement this properly.
- throw new UnsupportedOperationException("Not implemented yet.");
- }
-
- /**
- * Paints a scanline between x0 and x1. Override this when your backend
- * can efficiently draw/fill horizontal lines.
- *
- * @param x0 the left offset
- * @param x1 the right offset
- * @param y the scanline
- */
- public void renderScanline(int y, ScanlineCoverage c)
- {
- PaintContext pCtx = getPaintContext();
-
- int x0 = c.getMinX();
- int x1 = c.getMaxX();
- Raster paintRaster = pCtx.getRaster(x0, y, x1 - x0, 1);
-
- // Do the anti aliasing thing.
- float coverageAlpha = 0;
- float maxCoverage = c.getMaxCoverage();
- ColorModel cm = pCtx.getColorModel();
- DataBuffer db = paintRaster.getDataBuffer();
- Point loc = new Point(paintRaster.getMinX(), paintRaster.getMinY());
- SampleModel sm = paintRaster.getSampleModel();
- WritableRaster writeRaster = Raster.createWritableRaster(sm, db, loc);
- WritableRaster alphaRaster = cm.getAlphaRaster(writeRaster);
- int pixel;
- ScanlineCoverage.Iterator iter = c.iterate();
- while (iter.hasNext())
- {
- ScanlineCoverage.Range range = iter.next();
- coverageAlpha = range.getCoverage() / maxCoverage;
- if (coverageAlpha < 1.0)
- {
- for (int x = range.getXPos(); x < range.getXPosEnd(); x++)
- {
- pixel = alphaRaster.getSample(x, y, 0);
- pixel = (int) (pixel * coverageAlpha);
- alphaRaster.setSample(x, y, 0, pixel);
- }
- }
- }
- ColorModel paintColorModel = pCtx.getColorModel();
- CompositeContext cCtx = composite.createContext(paintColorModel,
- getColorModel(),
- renderingHints);
- WritableRaster raster = getDestinationRaster();
- WritableRaster targetChild = raster.createWritableTranslatedChild(-x0, -y);
-
- cCtx.compose(paintRaster, targetChild, targetChild);
- updateRaster(raster, x0, y, x1 - x0, 1);
- cCtx.dispose();
- }
-
-
- /**
- * Initializes this graphics object. This must be called by subclasses in
- * order to correctly initialize the state of this object.
- */
- protected void init()
- {
- setPaint(Color.BLACK);
- setFont(FONT);
- isOptimized = true;
- }
-
- /**
- * 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()
- {
- // TODO: Ideally we would fetch the xdrawable's surface pixels for
- // initialization of the raster.
- Rectangle db = getDeviceBounds();
- if (destinationRaster == null)
- {
- int[] bandMasks = new int[]{ 0xFF0000, 0xFF00, 0xFF };
- destinationRaster = Raster.createPackedRaster(DataBuffer.TYPE_INT,
- db.width, db.height,
- bandMasks, null);
- // Initialize raster with white.
- int x0 = destinationRaster.getMinX();
- int x1 = destinationRaster.getWidth() + x0;
- int y0 = destinationRaster.getMinY();
- int y1 = destinationRaster.getHeight() + y0;
- int numBands = destinationRaster.getNumBands();
- for (int y = y0; y < y1; y++)
- {
- for (int x = x0; x < x1; x++)
- {
- for (int b = 0; b < numBands; b++)
- destinationRaster.setSample(x, y, b, 255);
- }
- }
- }
- return destinationRaster;
- }
-
- /**
- * 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)
- {
- // Nothing to do here. Backends that need to update their surface
- // to reflect the change should override this method.
- }
-
- // Some helper methods.
-
- /**
- * Helper method to check and update the optimization conditions.
- */
- private void updateOptimization()
- {
- int transformType = transform.getType();
- boolean optimizedTransform = false;
- if (transformType == AffineTransform.TYPE_IDENTITY
- || transformType == AffineTransform.TYPE_TRANSLATION)
- optimizedTransform = true;
-
- boolean optimizedClip = (clip == null || clip instanceof Rectangle);
- isOptimized = optimizedClip
- && optimizedTransform && paint instanceof Color
- && composite == AlphaComposite.SrcOver
- && stroke.equals(new BasicStroke());
- }
-
- /**
- * Calculates the intersection of two rectangles. The result is stored
- * in <code>rect</code>. This is basically the same
- * like {@link Rectangle#intersection(Rectangle)}, only that it does not
- * create new Rectangle instances. The tradeoff is that you loose any data in
- * <code>rect</code>.
- *
- * @param x upper-left x coodinate of first rectangle
- * @param y upper-left y coodinate of first rectangle
- * @param w width of first rectangle
- * @param h height of first rectangle
- * @param rect a Rectangle object of the second rectangle
- *
- * @throws NullPointerException if rect is null
- *
- * @return a rectangle corresponding to the intersection of the
- * two rectangles. An empty rectangle is returned if the rectangles
- * do not overlap
- */
- private static Rectangle computeIntersection(int x, int y, int w, int h,
- Rectangle rect)
- {
- int x2 = rect.x;
- int y2 = rect.y;
- int w2 = rect.width;
- int h2 = rect.height;
-
- int dx = (x > x2) ? x : x2;
- int dy = (y > y2) ? y : y2;
- int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
- int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
-
- if (dw >= 0 && dh >= 0)
- rect.setBounds(dx, dy, dw, dh);
- else
- rect.setBounds(0, 0, 0, 0);
-
- return rect;
- }
-
- /**
- * Helper method to transform the clip. This is called by the various
- * transformation-manipulation methods to update the clip (which is in
- * userspace) accordingly.
- *
- * The transform usually is the inverse transform that was applied to the
- * graphics object.
- *
- * @param t the transform to apply to the clip
- */
- private void updateClip(AffineTransform t)
- {
- if (! (clip instanceof GeneralPath))
- clip = new GeneralPath(clip);
-
- GeneralPath p = (GeneralPath) clip;
- p.transform(t);
- }
-
- /**
- * Returns a free scanline converter from the pool.
- *
- * @return a scanline converter
- */
- private ScanlineConverter getScanlineConverter()
- {
- synchronized (scanlineConverters)
- {
- ScanlineConverter sc;
- if (scanlineConverters.size() > 0)
- {
- sc = scanlineConverters.removeFirst();
- }
- else
- {
- sc = new ScanlineConverter();
- }
- return sc;
- }
- }
-
- /**
- * Puts a scanline converter back in the pool.
- *
- * @param sc
- */
- private void freeScanlineConverter(ScanlineConverter sc)
- {
- synchronized (scanlineConverters)
- {
- scanlineConverters.addLast(sc);
- }
- }
-
- private PaintContext getPaintContext()
- {
- if (this.paintContext == null)
- {
- this.paintContext =
- this.foreground.createContext(getColorModel(),
- getDeviceBounds(),
- getClipBounds(),
- getTransform(),
- getRenderingHints());
- }
-
- return this.paintContext;
- }
-
- /**
- * Scales an image to the specified width and height. This should also
- * be used to implement
- * {@link Toolkit#prepareImage(Image, int, int, ImageObserver)}.
- * This uses {@link Toolkit#createImage(ImageProducer)} to create the actual
- * image.
- *
- * @param image the image to prepare
- * @param w the width
- * @param h the height
- *
- * @return the scaled image
- */
- public static Image prepareImage(Image image, int w, int h)
- {
- // Try to find cached scaled image.
- HashMap<Dimension,Image> scaledTable = imageCache.get(image);
- Dimension size = new Dimension(w, h);
- Image scaled = null;
- if (scaledTable != null)
- {
- scaled = scaledTable.get(size);
- }
- if (scaled == null)
- {
- // No cached scaled image. Start scaling image now.
- ImageProducer source = image.getSource();
- ReplicateScaleFilter scaler = new ReplicateScaleFilter(w, h);
- FilteredImageSource filteredSource =
- new FilteredImageSource(source, scaler);
- // Ideally, this should asynchronously scale the image.
- Image scaledImage =
- Toolkit.getDefaultToolkit().createImage(filteredSource);
- scaled = scaledImage;
- // Put scaled image in cache.
- if (scaledTable == null)
- {
- scaledTable = new HashMap<Dimension,Image>();
- imageCache.put(image, scaledTable);
- }
- scaledTable.put(size, scaledImage);
- }
- return scaled;
- }
-
-}