/*
* $Id$
*
* Copyright (C) 2003-2015 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.util;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
import java.awt.PaintContext;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.util.HashMap;
import java.util.Map;
import org.jnode.awt.JNodeToolkit;
import org.jnode.awt.font.FontManager;
import org.jnode.awt.font.TGlyphVector;
import org.jnode.driver.video.Surface;
import org.jnode.driver.video.util.AbstractSurface;
/**
* @author Levente S\u00e1ntha
*/
public abstract class SurfaceGraphics2D extends Graphics2D {
private static final BasicStroke DEFAULT_STROKE = new BasicStroke();
private static final HashMap<RenderingHints.Key, ?> DEFAULT_HINTS;
static {
HashMap<RenderingHints.Key, Object> hints = new HashMap<RenderingHints.Key, Object>();
hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT);
DEFAULT_HINTS = hints;
}
private final BasicSurfaceGraphics simpleGraphics;
private final AbstractSurface surface;
private int mode = Surface.PAINT_MODE;
private Color background = Color.WHITE;
private AffineTransform transform = new AffineTransform();
private Composite composite = AlphaComposite.SrcOver;
private Stroke stroke = DEFAULT_STROKE;
private Paint paint;
private Shape clip2D;
private RenderingHints renderingHints = new RenderingHints(DEFAULT_HINTS);
protected SurfaceGraphics2D(AbstractSurface surface) {
this.simpleGraphics = new BasicSurfaceGraphics(surface);
this.surface = surface;
}
protected SurfaceGraphics2D(SurfaceGraphics2D g) {
this.simpleGraphics = new BasicSurfaceGraphics(g.simpleGraphics);
this.surface = g.surface;
this.mode = g.mode;
this.background = g.background;
this.transform = g.transform;
this.composite = g.composite;
this.stroke = g.stroke;
this.paint = g.paint;
this.clip2D = g.clip2D;
this.renderingHints = g.renderingHints;
}
/**
* Sets the values of an arbitrary number of preferences for the
* rendering algorithms.
* Only values for the rendering hints that are present in the
* specified <code>Map</code> object are modified.
* All other preferences not present in the specified
* object are left unmodified.
* Hint categories include controls for rendering quality and
* overall time/quality trade-off in the rendering process.
* Refer to the <code>RenderingHints</code> class for definitions of
* some common keys and values.
*
* @param hints the rendering hints to be set
* @see java.awt.RenderingHints
*/
public void addRenderingHints(Map<?, ?> hints) {
renderingHints.putAll(hints);
}
/**
* Intersects the current <code>Clip</code> with the interior of the
* specified <code>Shape</code> and sets the <code>Clip</code> to the
* resulting intersection. The specified <code>Shape</code> is
* transformed with the current <code>Graphics2D</code>
* <code>Transform</code> before being intersected with the current
* <code>Clip</code>. This method is used to make the current
* <code>Clip</code> smaller.
* To make the <code>Clip</code> larger, use <code>setClip</code>.
* The <i>user clip</i> modified by this method is independent of the
* clipping associated with device bounds and visibility. If no clip has
* previously been set, or if the clip has been cleared using
* {@link java.awt.Graphics#setClip(java.awt.Shape) setClip} with a <code>null</code>
* argument, the specified <code>Shape</code> becomes the new
* user clip.
*
* @param s the <code>Shape</code> to be intersected with the current
* <code>Clip</code>. If <code>s</code> is <code>null</code>,
* this method clears the current <code>Clip</code>.
*/
public void clip(Shape s) {
//todo implement it
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.clip() not implemented\n");
/*
// todo attempt to fix metal ocean slider painting
AffineTransform t = new AffineTransform();
t.translate(simpleGraphics.origin.x, simpleGraphics.origin.y);
s = t.createTransformedShape(s);
Shape clip = simpleGraphics.getClip();
if (clip != null) {
Area as = new Area(s);
Area ac = new Area(clip);
as.intersect(ac);
s = as;
}
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.clip() 1 "+ s + "\n");
if (clip2D != null) {
Area as = new Area(s);
Area ac = new Area(clip2D);
as.intersect(ac);
s = as;
}
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.clip() 2 "+ s + "\n");
clip2D = s;
*/
}
/**
* Strokes the outline of a <code>Shape</code> using the settings of the
* current <code>Graphics2D</code> context. The rendering attributes
* applied include the <code>Clip</code>, <code>Transform</code>,
* <code>Paint</code>, <code>Composite</code> and
* <code>Stroke</code> attributes.
*
* @param s the <code>Shape</code> to be rendered
* @see #setStroke
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see #transform
* @see #setTransform
* @see #clip
* @see #setClip
* @see #setComposite
*/
public void draw(Shape s) {
//todo G2D clip & transfom
//org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.draw() not implemented\n");
Point p = simpleGraphics.origin;
AffineTransform t = AffineTransform.getTranslateInstance(p.x, p.y);
surface.draw(s, simpleGraphics.getClip(), t, getColor(), mode);
}
/**
* Renders the text of the specified
* {@link java.awt.font.GlyphVector} using
* the <code>Graphics2D</code> context's rendering attributes.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, <code>Paint</code>, and
* <code>Composite</code> attributes. The <code>GlyphVector</code>
* specifies individual glyphs from a {@link java.awt.Font}.
* The <code>GlyphVector</code> can also contain the glyph positions.
* This is the fastest way to render a set of characters to the
* screen.
*
* @param g the <code>GlyphVector</code> to be rendered
* @param x the x position in User Space where the glyphs should
* be rendered
* @param y the y position in User Space where the glyphs should
* be rendered
* @throws NullPointerException if <code>g</code> is <code>null</code>.
* @see java.awt.Font#createGlyphVector
* @see java.awt.font.GlyphVector
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see #setTransform
* @see #setComposite
* @see #setClip
*/
public void drawGlyphVector(GlyphVector g, float x, float y) {
//todo improve it
if (g instanceof TGlyphVector) {
char[] chars = ((TGlyphVector) g).getChars();
simpleGraphics.drawChars(chars, 0, chars.length, (int) x, (int) y);
} else {
org.jnode.vm.Unsafe.debug("Unsupported GlyphVector type: " +
(g == null ? "null" : g.getClass().getName()) + "\n");
}
}
/**
* Renders a <code>BufferedImage</code> that is
* filtered with a
* {@link java.awt.image.BufferedImageOp}.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>
* and <code>Composite</code> attributes. This is equivalent to:
* <pre>
* img1 = op.filter(img, null);
* drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null);
* </pre>
*
* @param op the filter to be applied to the image before rendering
* @param img the specified <code>BufferedImage</code> to be rendered.
* This method does nothing if <code>img</code> is null.
* @param x the x coordinate of the location in user space where
* the upper left corner of the image is rendered
* @param y the y coordinate of the location in user space where
* the upper left corner of the image is rendered
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
//todo implement it
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage() - 0 not implemented\n");
}
/**
* Renders an image, applying a transform from image space into user space
* before drawing.
* The transformation from user space into device space is done with
* the current <code>Transform</code> in the <code>Graphics2D</code>.
* The specified transformation is applied to the image before the
* transform attribute in the <code>Graphics2D</code> context is applied.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, and <code>Composite</code> attributes.
* Note that no rendering is done if the specified transform is
* noninvertible.
*
* @param img the specified image to be rendered.
* This method does nothing if <code>img</code> is null.
* @param xform the transformation from image space into user space
* @param obs the {@link java.awt.image.ImageObserver}
* to be notified as more of the <code>Image</code>
* is converted
* @return <code>true</code> if the <code>Image</code> is
* fully loaded and completely rendered, or if it's null;
* <code>false</code> if the <code>Image</code> is still being loaded.
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
//todo implement it
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage() - 00 not implemented\n");
return false;
}
/**
* Renders a
* {@link java.awt.image.renderable.RenderableImage},
* applying a transform from image space into user space before drawing.
* The transformation from user space into device space is done with
* the current <code>Transform</code> in the <code>Graphics2D</code>.
* The specified transformation is applied to the image before the
* transform attribute in the <code>Graphics2D</code> context is applied.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, and <code>Composite</code> attributes. Note
* that no rendering is done if the specified transform is
* noninvertible.
* <p/>
* Rendering hints set on the <code>Graphics2D</code> object might
* be used in rendering the <code>RenderableImage</code>.
* If explicit control is required over specific hints recognized by a
* specific <code>RenderableImage</code>, or if knowledge of which hints
* are used is required, then a <code>RenderedImage</code> should be
* obtained directly from the <code>RenderableImage</code>
* and rendered using
* {@link #drawRenderedImage(java.awt.image.RenderedImage , java.awt.geom.AffineTransform) drawRenderedImage}.
*
* @param img the image to be rendered. This method does
* nothing if <code>img</code> is null.
* @param xform the transformation from image space into user space
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
* @see #drawRenderedImage
*/
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
//todo implement it
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawRenderableImage() not implemented\n");
}
/**
* Renders a {@link java.awt.image.RenderedImage},
* applying a transform from image
* space into user space before drawing.
* The transformation from user space into device space is done with
* the current <code>Transform</code> in the <code>Graphics2D</code>.
* The specified transformation is applied to the image before the
* transform attribute in the <code>Graphics2D</code> context is applied.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, and <code>Composite</code> attributes. Note
* that no rendering is done if the specified transform is
* noninvertible.
*
* @param img the image to be rendered. This method does
* nothing if <code>img</code> is null.
* @param xform the transformation from image space into user space
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
//todo implement it
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawRenderedImage() not implemented\n");
}
/**
* Renders the text of the specified iterator applying its attributes
* in accordance with the specification of the {@link java.awt.font.TextAttribute} class.
* <p/>
* The baseline of the first character is at position
* (<i>x</i>, <i>y</i>) in User Space.
* For characters in script systems such as Hebrew and Arabic,
* the glyphs can be rendered from right to left, in which case the
* coordinate supplied is the location of the leftmost character
* on the baseline.
*
* @param iterator the iterator whose text is to be rendered
* @param x the x coordinate where the iterator's text is to be
* rendered
* @param y the y coordinate where the iterator's text is to be
* rendered
* @throws NullPointerException if <code>iterator</code> is
* <code>null</code>
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see #setTransform
* @see #setComposite
* @see #setClip
*/
public void drawString(AttributedCharacterIterator iterator, float x, float y) {
simpleGraphics.drawString(iterator, (int) x, (int) y);
}
/**
* Renders the text specified by the specified <code>String</code>,
* using the current text attribute state in the <code>Graphics2D</code> context.
* The baseline of the first character is at position
* (<i>x</i>, <i>y</i>) in the User Space.
* The rendering attributes applied include the <code>Clip</code>,
* <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
* <code>Composite</code> attributes. For characters in script systems
* such as Hebrew and Arabic, the glyphs can be rendered from right to
* left, in which case the coordinate supplied is the location of the
* leftmost character on the baseline.
*
* @param str the <code>String</code> to be rendered
* @param x the x coordinate of the location where the
* <code>String</code> should be rendered
* @param y the y coordinate of the location where the
* <code>String</code> should be rendered
* @throws NullPointerException if <code>str</code> is
* <code>null</code>
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see java.awt.Graphics#setFont
* @see #setTransform
* @see #setComposite
* @see #setClip
*/
public void drawString(String str, float x, float y) {
// we should call "simpleGraphics.drawString(str, (int) x, (int) y);"
// but since it doesn't handle transform, we have to implement ourself the rendering
// TODO should we move that code to simpleGraphics implementation ?
JNodeToolkit tk = (JNodeToolkit) Toolkit.getDefaultToolkit();
FontManager fm = tk.getFontManager();
fm.drawText(surface, getClip(), getTransform(), str, getFont(), (int) x, (int) y, getColor());
}
/**
* Fills the interior of a <code>Shape</code> using the settings of the
* <code>Graphics2D</code> context. The rendering attributes applied
* include the <code>Clip</code>, <code>Transform</code>,
* <code>Paint</code>, and <code>Composite</code>.
*
* @param s the <code>Shape</code> to be filled
* @see #setPaint
* @see java.awt.Graphics#setColor
* @see #transform
* @see #setTransform
* @see #setComposite
* @see #clip
* @see #setClip
*/
public void fill(Shape s) {
//org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.fill() todo G2D clip & transfom\n");
//todo G2D clip & transfom
Point p = simpleGraphics.origin;
AffineTransform t = AffineTransform.getTranslateInstance(p.x, p.y);
surface.fill(s, simpleGraphics.getClip(), t, getColor(), mode);
}
/**
* Returns the background color used for clearing a region.
*
* @return the current <code>Graphics2D</code> <code>Color</code>,
* which defines the background color.
* @see #setBackground
*/
public Color getBackground() {
return background;
}
/**
* Returns the current <code>Composite</code> in the
* <code>Graphics2D</code> context.
*
* @return the current <code>Graphics2D</code> <code>Composite</code>,
* which defines a compositing style.
* @see #setComposite
*/
public Composite getComposite() {
return composite;
}
/**
* Returns the device configuration associated with this
* <code>Graphics2D</code>.
*
* @return the device configuration of this <code>Graphics2D</code>.
*/
public GraphicsConfiguration getDeviceConfiguration() {
//todo implement it
return null;
}
/**
* Get the rendering context of the <code>Font</code> within this
* <code>Graphics2D</code> context.
* The {@link java.awt.font.FontRenderContext}
* encapsulates application hints such as anti-aliasing and
* fractional metrics, as well as target device specific information
* such as dots-per-inch. This information should be provided by the
* application when using objects that perform typographical
* formatting, such as <code>Font</code> and
* <code>TextLayout</code>. This information should also be provided
* by applications that perform their own layout and need accurate
* measurements of various characteristics of glyphs such as advance
* and line height when various rendering hints have been applied to
* the text rendering.
*
* @return a reference to an instance of FontRenderContext.
* @see java.awt.font.FontRenderContext
* @see java.awt.Font#createGlyphVector
* @see java.awt.font.TextLayout
* @since 1.2
*/
public FontRenderContext getFontRenderContext() {
//todo implement it
//org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.getFontRendererContext() not implemented\n");
//return null;
return new FontRenderContext(getTransform(), true, false);
}
/**
* Returns the current <code>Paint</code> of the
* <code>Graphics2D</code> context.
*
* @return the current <code>Graphics2D</code> <code>Paint</code>,
* which defines a color or pattern.
* @see #setPaint
* @see java.awt.Graphics#setColor
*/
public Paint getPaint() {
if (paint == null)
return simpleGraphics.getColor();
else
return paint;
}
/**
* Returns the value of a single preference for the rendering algorithms.
* Hint categories include controls for rendering quality and overall
* time/quality trade-off in the rendering process. Refer to the
* <code>RenderingHints</code> class for definitions of some common
* keys and values.
*
* @param hintKey the key corresponding to the hint to get.
* @return an object representing the value for the specified hint key.
* Some of the keys and their associated values are defined in the
* <code>RenderingHints</code> class.
* @see java.awt.RenderingHints
* @see #setRenderingHint(java.awt.RenderingHints.Key, Object)
*/
public Object getRenderingHint(RenderingHints.Key hintKey) {
return renderingHints.get(hintKey);
}
/**
* Gets the preferences for the rendering algorithms. Hint categories
* include controls for rendering quality and overall time/quality
* trade-off in the rendering process.
* Returns all of the hint key/value pairs that were ever specified in
* one operation. Refer to the
* <code>RenderingHints</code> class for definitions of some common
* keys and values.
*
* @return a reference to an instance of <code>RenderingHints</code>
* that contains the current preferences.
* @see java.awt.RenderingHints
* @see #setRenderingHints(java.util.Map)
*/
public RenderingHints getRenderingHints() {
return renderingHints;
}
/**
* Returns the current <code>Stroke</code> in the
* <code>Graphics2D</code> context.
*
* @return the current <code>Graphics2D</code> <code>Stroke</code>,
* which defines the line style.
* @see #setStroke
*/
public Stroke getStroke() {
return stroke;
}
/**
* Returns a copy of the current <code>Transform</code> in the
* <code>Graphics2D</code> context.
*
* @return the current <code>AffineTransform</code> in the
* <code>Graphics2D</code> context.
* @see #transform
* @see #setTransform
*/
public AffineTransform getTransform() {
return new AffineTransform(transform);
}
/**
* Checks whether or not the specified <code>Shape</code> intersects
* the specified {@link java.awt.Rectangle}, which is in device
* space. If <code>onStroke</code> is false, this method checks
* whether or not the interior of the specified <code>Shape</code>
* intersects the specified <code>Rectangle</code>. If
* <code>onStroke</code> is <code>true</code>, this method checks
* whether or not the <code>Stroke</code> of the specified
* <code>Shape</code> outline intersects the specified
* <code>Rectangle</code>.
* The rendering attributes taken into account include the
* <code>Clip</code>, <code>Transform</code>, and <code>Stroke</code>
* attributes.
*
* @param rect the area in device space to check for a hit
* @param s the <code>Shape</code> to check for a hit
* @param onStroke flag used to choose between testing the
* stroked or the filled shape. If the flag is <code>true</code>, the
* <code>Stroke</code> oultine is tested. If the flag is
* <code>false</code>, the filled <code>Shape</code> is tested.
* @return <code>true</code> if there is a hit; <code>false</code>
* otherwise.
* @see #setStroke
* @see #fill
* @see #draw
* @see #transform
* @see #setTransform
* @see #clip
* @see #setClip
*/
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
//todo implement it
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.hit() not implemented\n");
return false;
}
/**
* Concatenates the current <code>Graphics2D</code>
* <code>Transform</code> with a rotation transform.
* Subsequent rendering is rotated by the specified radians relative
* to the previous origin.
* This is equivalent to calling <code>transform(R)</code>, where R is an
* <code>AffineTransform</code> represented by the following matrix:
* <pre>
* [ cos(theta) -sin(theta) 0 ]
* [ sin(theta) cos(theta) 0 ]
* [ 0 0 1 ]
* </pre>
* Rotating with a positive angle theta rotates points on the positive
* x axis toward the positive y axis.
*
* @param theta the angle of rotation in radians
*/
public void rotate(double theta) {
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.rotate1() invoked\n");
transform.concatenate(AffineTransform.getRotateInstance(theta));
}
/**
* Concatenates the current <code>Graphics2D</code>
* <code>Transform</code> with a translated rotation
* transform. Subsequent rendering is transformed by a transform
* which is constructed by translating to the specified location,
* rotating by the specified radians, and translating back by the same
* amount as the original translation. This is equivalent to the
* following sequence of calls:
* <pre>
* translate(x, y);
* rotate(theta);
* translate(-x, -y);
* </pre>
* Rotating with a positive angle theta rotates points on the positive
* x axis toward the positive y axis.
*
* @param theta the angle of rotation in radians
* @param x the x coordinate of the origin of the rotation
* @param y the y coordinate of the origin of the rotation
*/
public void rotate(double theta, double x, double y) {
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.rotate2() invoked\n");
transform.concatenate(AffineTransform.getRotateInstance(theta, x, y));
}
/**
* Concatenates the current <code>Graphics2D</code>
* <code>Transform</code> with a scaling transformation
* Subsequent rendering is resized according to the specified scaling
* factors relative to the previous scaling.
* This is equivalent to calling <code>transform(S)</code>, where S is an
* <code>AffineTransform</code> represented by the following matrix:
* <pre>
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param sx the amount by which X coordinates in subsequent
* rendering operations are multiplied relative to previous
* rendering operations.
* @param sy the amount by which Y coordinates in subsequent
* rendering operations are multiplied relative to previous
* rendering operations.
*/
public void scale(double sx, double sy) {
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.scale() invoked\n");
transform.concatenate(AffineTransform.getScaleInstance(sx, sy));
}
/**
* Sets the background color for the <code>Graphics2D</code> context.
* The background color is used for clearing a region.
* When a <code>Graphics2D</code> is constructed for a
* <code>Component</code>, the background color is
* inherited from the <code>Component</code>. Setting the background color
* in the <code>Graphics2D</code> context only affects the subsequent
* <code>clearRect</code> calls and not the background color of the
* <code>Component</code>. To change the background
* of the <code>Component</code>, use appropriate methods of
* the <code>Component</code>.
*
* @param color the background color that isused in
* subsequent calls to <code>clearRect</code>
* @see #getBackground
* @see java.awt.Graphics#clearRect
*/
public void setBackground(Color color) {
this.background = color;
}
/**
* Sets the <code>Composite</code> for the <code>Graphics2D</code> context.
* The <code>Composite</code> is used in all drawing methods such as
* <code>drawImage</code>, <code>drawString</code>, <code>draw</code>,
* and <code>fill</code>. It specifies how new pixels are to be combined
* with the existing pixels on the graphics device during the rendering
* process.
* <p>If this <code>Graphics2D</code> context is drawing to a
* <code>Component</code> on the display screen and the
* <code>Composite</code> is a custom object rather than an
* instance of the <code>AlphaComposite</code> class, and if
* there is a security manager, its <code>checkPermission</code>
* method is called with an <code>AWTPermission("readDisplayPixels")</code>
* permission.
*
* @param comp the <code>Composite</code> object to be used for rendering
* @throws SecurityException if a custom <code>Composite</code> object is being
* used to render to the screen and a security manager
* is set and its <code>checkPermission</code> method
* does not allow the operation.
* @see java.awt.Graphics#setXORMode
* @see java.awt.Graphics#setPaintMode
* @see #getComposite
* @see java.awt.AlphaComposite
* @see SecurityManager#checkPermission
* @see java.awt.AWTPermission
*/
public void setComposite(Composite comp) {
this.composite = comp;
}
/**
* Sets the <code>Paint</code> attribute for the
* <code>Graphics2D</code> context. Calling this method
* with a <code>null</code> <code>Paint</code> object does
* not have any effect on the current <code>Paint</code> attribute
* of this <code>Graphics2D</code>.
*
* @param paint the <code>Paint</code> object to be used to generate
* color during the rendering process, or <code>null</code>
* @see java.awt.Graphics#setColor
* @see #getPaint
* @see java.awt.GradientPaint
* @see java.awt.TexturePaint
*/
public void setPaint(Paint paint) {
if (paint == null)
return;
this.paint = paint;
if (paint instanceof Color) {
simpleGraphics.setColor((Color) paint);
}
}
/**
* Sets the value of a single preference for the rendering algorithms.
* Hint categories include controls for rendering quality and overall
* time/quality trade-off in the rendering process. Refer to the
* <code>RenderingHints</code> class for definitions of some common
* keys and values.
*
* @param hintKey the key of the hint to be set.
* @param hintValue the value indicating preferences for the specified
* hint category.
* @see #getRenderingHint(java.awt.RenderingHints.Key)
* @see java.awt.RenderingHints
*/
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) {
renderingHints.put(hintKey, hintValue);
}
/**
* Replaces the values of all preferences for the rendering
* algorithms with the specified <code>hints</code>.
* The existing values for all rendering hints are discarded and
* the new set of known hints and values are initialized from the
* specified {@link java.util.Map} object.
* Hint categories include controls for rendering quality and
* overall time/quality trade-off in the rendering process.
* Refer to the <code>RenderingHints</code> class for definitions of
* some common keys and values.
*
* @param hints the rendering hints to be set
* @see #getRenderingHints
* @see java.awt.RenderingHints
*/
public void setRenderingHints(Map<?, ?> hints) {
renderingHints.clear();
renderingHints.putAll(hints);
}
/**
* Sets the <code>Stroke</code> for the <code>Graphics2D</code> context.
*
* @param s the <code>Stroke</code> object to be used to stroke a
* <code>Shape</code> during the rendering process
* @see java.awt.BasicStroke
* @see #getStroke
*/
public void setStroke(Stroke s) {
this.stroke = s;
}
/**
* Overwrites the Transform in the <code>Graphics2D</code> context.
* WARNING: This method should <b>never</b> be used to apply a new
* coordinate transform on top of an existing transform because the
* <code>Graphics2D</code> might already have a transform that is
* needed for other purposes, such as rendering Swing
* components or applying a scaling transformation to adjust for the
* resolution of a printer.
* <p>To add a coordinate transform, use the
* <code>transform</code>, <code>rotate</code>, <code>scale</code>,
* or <code>shear</code> methods. The <code>setTransform</code>
* method is intended only for restoring the original
* <code>Graphics2D</code> transform after rendering, as shown in this
* example:
* <pre><blockquote>
* // Get the current transform
* AffineTransform saveAT = g2.getTransform();
* // Perform transformation
* g2d.transform(...);
* // Render
* g2d.draw(...);
* // Restore original transform
* g2d.setTransform(saveAT);
* </blockquote></pre>
*
* @param Tx the <code>AffineTransform</code> that was retrieved
* from the <code>getTransform</code> method
* @see #transform
* @see #getTransform
* @see java.awt.geom.AffineTransform
*/
public void setTransform(AffineTransform Tx) {
//org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.setTransform() invoked\n");
this.transform = new AffineTransform(Tx);
}
/**
* Concatenates the current <code>Graphics2D</code>
* <code>Transform</code> with a shearing transform.
* Subsequent renderings are sheared by the specified
* multiplier relative to the previous position.
* This is equivalent to calling <code>transform(SH)</code>, where SH
* is an <code>AffineTransform</code> represented by the following
* matrix:
* <pre>
* [ 1 shx 0 ]
* [ shy 1 0 ]
* [ 0 0 1 ]
* </pre>
*
* @param shx the multiplier by which coordinates are shifted in
* the positive X axis direction as a function of their Y coordinate
* @param shy the multiplier by which coordinates are shifted in
* the positive Y axis direction as a function of their X coordinate
*/
public void shear(double shx, double shy) {
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.shear() invoked\n");
transform.concatenate(AffineTransform.getShearInstance(shx, shy));
}
/**
* Composes an <code>AffineTransform</code> object with the
* <code>Transform</code> in this <code>Graphics2D</code> according
* to the rule last-specified-first-applied. If the current
* <code>Transform</code> is Cx, the result of composition
* with Tx is a new <code>Transform</code> Cx'. Cx' becomes the
* current <code>Transform</code> for this <code>Graphics2D</code>.
* Transforming a point p by the updated <code>Transform</code> Cx' is
* equivalent to first transforming p by Tx and then transforming
* the result by the original <code>Transform</code> Cx. In other
* words, Cx'(p) = Cx(Tx(p)). A copy of the Tx is made, if necessary,
* so further modifications to Tx do not affect rendering.
*
* @param Tx the <code>AffineTransform</code> object to be composed with
* the current <code>Transform</code>
* @see #setTransform
* @see java.awt.geom.AffineTransform
*/
public void transform(AffineTransform Tx) {
//org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.transform() invoked\n");
transform.concatenate(Tx);
}
/**
* Concatenates the current
* <code>Graphics2D</code> <code>Transform</code>
* with a translation transform.
* Subsequent rendering is translated by the specified
* distance relative to the previous position.
* This is equivalent to calling transform(T), where T is an
* <code>AffineTransform</code> represented by the following matrix:
* <pre>
* [ 1 0 tx ]
* [ 0 1 ty ]
* [ 0 0 1 ]
* </pre>
*
* @param tx the distance to translate along the x-axis
* @param ty the distance to translate along the y-axis
*/
public void translate(double tx, double ty) {
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.translate() invoked\n");
transform.concatenate(AffineTransform.getTranslateInstance(tx, ty));
}
//Basic Graphics Related Methods
public Graphics create() {
return simpleGraphics.create();
}
public void translate(int x, int y) {
simpleGraphics.translate(x, y);
}
public Color getColor() {
return simpleGraphics.getColor();
}
public void setColor(Color c) {
simpleGraphics.setColor(c);
}
public void setPaintMode() {
simpleGraphics.setPaintMode();
}
public void setXORMode(Color c1) {
simpleGraphics.setXORMode(c1);
}
public Font getFont() {
return simpleGraphics.getFont();
}
public void setFont(Font font) {
simpleGraphics.setFont(font);
}
public FontMetrics getFontMetrics(Font f) {
return simpleGraphics.getFontMetrics(f);
}
public Rectangle getClipBounds() {
return simpleGraphics.getClipBounds();
}
public void clipRect(int x, int y, int width, int height) {
simpleGraphics.clipRect(x, y, width, height);
}
public void setClip(int x, int y, int width, int height) {
simpleGraphics.setClip(x, y, width, height);
}
public Shape getClip() {
return simpleGraphics.getClip();
}
public void setClip(Shape clip) {
simpleGraphics.setClip(clip);
//todo improve support for Graphics2D
//clip2D = null;
}
public void copyArea(int x, int y, int width, int height, int dx, int dy) {
simpleGraphics.copyArea(x, y, width, height, dx, dy);
}
public void drawLine(int x1, int y1, int x2, int y2) {
simpleGraphics.drawLine(x1, y1, x2, y2);
}
public void fillRect(int x, int y, int width, int height) {
// if(clip2D == null){
if (paint == null) {
simpleGraphics.fillRect(x, y, width, height);
} else {
x = x + simpleGraphics.origin.x;
y = y + simpleGraphics.origin.y;
BufferedImage img = getFillerImage(x, y, width, height);
//org.jnode.vm.Unsafe.debug("SurfaceGraphics2D - 2\n");
drawImage(img, x, y, background, null);
}
/*
todo attempt to fix metal ocean slider painting
(Graphics2D.clip() is used with non-rectangular shape + fillRect() with gradient paint)
} else {
AffineTransform af = new AffineTransform();
af.translate(simpleGraphics.origin.x, simpleGraphics.origin.y);
if(paint == null){
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D - 3\n");
//surface.fill(new Rectangle(x, y, width, height), clip2D, af, simpleGraphics.getColor(),
// Surface.PAINT_MODE);
x = x + simpleGraphics.origin.x;
y = y + simpleGraphics.origin.y;
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D - 4\n");
int rgb = simpleGraphics.getColor().getRGB();
for(int i = 0; i < width; i++){
for(int j = 0; j < height; j++){
if(clip2D.contains(x + i , y + j)){
surface.drawPixel(x + i, y + j, rgb, Surface.PAINT_MODE);
}
}
}
} else {
x = x + simpleGraphics.origin.x;
y = y + simpleGraphics.origin.y;
org.jnode.vm.Unsafe.debug("SurfaceGraphics2D - 4\n");
BufferedImage img = getFillerImage(x, y, width, height);
for(int i = 0; i < width; i++){
for(int j = 0; j < height; j++){
if(clip2D.contains(x + i , y + j)){
int rgb = img.getRGB(i, j);
surface.drawPixel(x + i, y + j, rgb, Surface.PAINT_MODE);
}
}
}
}
}
*/
}
private BufferedImage getFillerImage(int x, int y, int width, int height) {
ColorModel scm = surface.getColorModel();
PaintContext pc = paint.createContext(scm, new Rectangle(0, 0, 800, 600),
new Rectangle(0, 0, 800, 600), new AffineTransform(), renderingHints);
Raster raster = pc.getRaster(x, y, width, height);
ColorModel cm = pc.getColorModel();
WritableRaster raster2 = scm.createCompatibleWritableRaster(width, height);
Object de1 = null;
Object de2 = null;
int[] comps = new int[4];
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++) {
de1 = raster.getDataElements(i, j, de1);
comps = cm.getComponents(de1, comps, 0);
comps[3] = 0xFF;
de2 = scm.getDataElements(comps, 0, de2);
raster2.setDataElements(i, j, de2);
}
return new BufferedImage(scm, raster2, cm.isAlphaPremultiplied(), null);
}
public void clearRect(int x, int y, int width, int height) {
simpleGraphics.clearRect(x, y, width, height);
/*
Rectangle r = new Rectangle(x, y, width, height);
simpleGraphics._transform(r);
if(simpleGraphics.clip != null)
r = simpleGraphics.clip.intersection(r);
surface.fillRect(r.x, r.y, r.width, r.height, background.getRGB(), Surface.PAINT_MODE);
surface.update(r.x, r.y, r.width, r.height);
*/
}
public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
draw(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
}
public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
}
public void drawOval(int x, int y, int width, int height) {
draw(new Ellipse2D.Float(x, y, width, height));
}
public void fillOval(int x, int y, int width, int height) {
fill(new Ellipse2D.Float(x, y, width, height));
}
public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
draw(new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN));
}
public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
fill(new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN));
}
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
final GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO, nPoints * 2);
path.moveTo(xPoints[0], yPoints[0]);
for (int i = 1; i < nPoints; i++) {
path.lineTo(xPoints[i], yPoints[i]);
}
draw(path);
}
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
draw(new Polygon(xPoints, yPoints, nPoints));
}
public void drawPolygon(Polygon p) {
draw(p);
}
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
fill(new Polygon(xPoints, yPoints, nPoints));
}
public void fillPolygon(Polygon p) {
fill(p);
}
public void drawString(String str, int x, int y) {
simpleGraphics.drawString(str, x, y);
}
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
simpleGraphics.drawString(iterator, x, y);
}
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
// org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage()-1\n");
return simpleGraphics.drawImage(img, x, y, observer);
}
public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
// org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage()-2\n");
return simpleGraphics.drawImage(img, x, y, width, height, observer);
}
public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
// org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage()-3\n");
return simpleGraphics.drawImage(img, x, y, bgcolor, observer);
}
public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
// org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage()-4\n");
return simpleGraphics.drawImage(img, x, y, width, height, bgcolor, observer);
}
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
ImageObserver observer) {
// org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage()-5\n");
return simpleGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
}
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) {
// org.jnode.vm.Unsafe.debug("SurfaceGraphics2D.drawImage()-6\n");
return simpleGraphics.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer);
}
public void dispose() {
simpleGraphics.dispose();
}
}