FileDocCategorySizeDatePackage
Graphics.javaAPI DocJ2ME MIDP 2.073606Thu Nov 07 12:02:26 GMT 2002javax.microedition.lcdui

Graphics.java

/*
 * @(#)Graphics.java	1.84 02/09/10 @(#)
 *
 * Copyright (c) 1999-2002 Sun Microsystems, Inc.  All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 */

package javax.microedition.lcdui;

/**
 * Provides simple 2D geometric rendering capability.
 *
 * <p>Drawing primitives are provided for text, images, lines, rectangles,
 * and arcs. Rectangles and arcs may also be filled with a solid color.
 * Rectangles may also be specified with rounded corners. </p>
 *
 * <p>A <code>24</code>-bit color model is provided, with
 * <code>8</code> bits for each of red, green, and
 * blue components of a color. Not all devices support a full
 * <code>24</code> bits' worth
 * of color and thus they will map colors requested by the application into
 * colors available on the device. Facilities are provided in the
 * {@link
 * Display Display} class for obtaining device characteristics, such
 * as
 * whether color is available and how many distinct gray levels are
 * available.
 * Applications may also use {@link Graphics#getDisplayColor(int)
 * getDisplayColor()} to obtain the actual color that would be displayed
 * for a requested color.
 * This enables applications to adapt their behavior to a device without
 * compromising device independence. </p>
 *
 * <p>For all rendering operations, source pixels are always combined with
 * destination pixels using the <em>Source Over Destination</em> rule
 * [Porter-Duff].  Other schemes for combining source pixels with destination
 * pixels, such as raster-ops, are not provided.</p>
 *
 * <p>For the text, line, rectangle, and arc drawing and filling primitives,
 * the source pixel is a pixel representing the current color of the graphics
 * object being used for rendering.  This pixel is always considered to be
 * fully opaque.  With source pixel that is always fully opaque, the Source
 * Over Destination rule has the effect of pixel replacement, where
 * destination pixels are simply replaced with the source pixel from the
 * graphics object.</p>
 *
 * <p>The {@link #drawImage drawImage()} and {@link #drawRegion drawRegion()}
 * methods use an image as the source for rendering operations instead of the
 * current color of the graphics object.  In this context, the Source Over
 * Destination rule has the following properties: a fully opaque pixel in the
 * source must replace the destination pixel, a fully transparent pixel in the
 * source must leave the destination pixel unchanged, and a semitransparent
 * pixel in the source must be alpha blended with the destination pixel.
 * Alpha blending of semitransparent pixels is required.  If an implementation
 * does not support alpha blending, it must remove all semitransparency from
 * image source data at the time the image is created.  See <a
 * href="Image.html#alpha">Alpha Processing</a> for further discussion.
 *
 * <p>The destinations of all graphics rendering are considered to consist
 * entirely of fully opaque pixels.  A property of the Source Over Destination
 * rule is that compositing any pixel with a fully opaque destination pixel
 * always results in a fully opaque destination pixel.  This has the effect of
 * confining full and partial transparency to immutable images, which may only
 * be used as the source for rendering operations.</p>
 *
 * <p>
 * Graphics may be rendered directly to the display or to an off-screen
 * image buffer. The destination of rendered graphics depends on the
 * provenance of the graphics object. A graphics object for rendering
 * to the display is passed to the <code>Canvas</code> object's
 * {@link Canvas#paint(Graphics) paint()}
 * method. This is the only means by which a graphics object may
 * be obtained whose destination is the display. Furthermore, applications
 * may draw using this graphics object only for the duration of the
 * <code>paint()</code> method. </p>
 * <p>
 * A graphics object for rendering to an off-screen image buffer may
 * be obtained by calling the
 * {@link Image#getGraphics() getGraphics()}
 * method on the desired image.
 * A graphics object so obtained may be held indefinitely
 * by the application, and requests may be issued on this graphics
 * object at any time. </p>
 *<p>
 * The default coordinate system's origin is at the
 * upper left-hand corner of the destination. The X-axis direction is
 * positive towards the right, and the Y-axis direction is positive
 * downwards. Applications may assume that horizontal and vertical
 * distances in the coordinate system represent equal distances on the
 * actual device display, that is, pixels are square. A facility is provided
 * for translating the origin of the coordinate system.
 * All coordinates are specified as integers. </p>
 * <p>
 * The coordinate system represents locations between pixels, not the
 * pixels themselves. Therefore, the first pixel in the upper left corner
 * of the display lies in the square bounded by coordinates
 * <code>(0,0) , (1,0) , (0,1) , (1,1)</code>. </p>
 * <p>
 * Under this definition, the semantics for fill operations are clear.
 * Since coordinate grid lines lie between pixels, fill operations
 * affect pixels that lie entirely within the region bounded by the
 * coordinates of the operation. For example, the operation </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.fillRect(0, 0, 3, 2)    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <P>
 * paints exactly six pixels.  (In this example, and in all subsequent
 * examples, the variable <code>g</code> is assumed to contain a
 * reference to a
 * <code>Graphics</code> object.) </p>
 * <p>
 * Each character of a font contains a set of pixels that forms the shape of
 * the character.  When a character is painted, the pixels forming the
 * character's shape are filled with the <code>Graphics</code>
 * object's current color, and
 * the pixels not part of the character's shape are left untouched.
 * The text drawing calls
 * {@link #drawChar drawChar()},
 * {@link #drawChars drawChars()},
 * {@link #drawString drawString()}, and
 * {@link #drawSubstring drawSubstring()}
 * all draw text in this manner. </p>
 * <p>
 * Lines, arcs, rectangles, and rounded rectangles may be drawn with either a
 * <code>SOLID</code> or a <code>DOTTED</code> stroke style, as set by
 * the {@link #setStrokeStyle
 * setStrokeStyle()} method.  The stroke style does not affect fill, text, and
 * image operations. </p>
 * <p>
 * For the <code>SOLID</code> stroke style,
 * drawing operations are performed with a one-pixel wide pen that fills
 * the pixel immediately
 * below and to the right of the specified coordinate. Drawn lines
 * touch pixels at both endpoints. Thus, the operation </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.drawLine(0, 0, 0, 0);    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <p>
 * paints exactly one pixel, the first pixel in the upper left corner
 * of the display. </p>
 * <p>
 * Drawing operations under the <code>DOTTED</code> stroke style will
 * touch a subset of
 * pixels that would have been touched under the <code>SOLID</code>
 * stroke style.  The
 * frequency and length of dots is implementation-dependent.  The endpoints of
 * lines and arcs are not guaranteed to be drawn, nor are the corner points of
 * rectangles guaranteed to be drawn.  Dots are drawn by painting with the
 * current color; spaces between dots are left untouched. </p>
 * <p>
 * An artifact of the coordinate system is that the area affected by a fill
 * operation differs slightly from the area affected by a draw operation given
 * the same coordinates. For example, consider the operations </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.fillRect(x, y, w, h); // 1
 *    g.drawRect(x, y, w, h); // 2    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <P>
 * Statement (1) fills a rectangle <code>w</code> pixels wide and
 * <code>h</code> pixels high.
 * Statement (2) draws a rectangle whose left and top
 * edges are within the area filled by statement (1). However, the
 * bottom and right edges lie one pixel outside the filled area.
 * This is counterintuitive, but it preserves the invariant that </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.drawLine(x, y, x+w, y);
 *    g.drawLine(x+w, y, x+w, y+h);
 *    g.drawLine(x+w, y+h, x, y+h);
 *    g.drawLine(x, y+h, x, y);     </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <P>
 * has an effect identical to statement (2) above. </p>
 * <p>
 * The exact pixels painted by <code>drawLine()</code> and
 * <code>drawArc()</code> are not
 * specified. Pixels touched by a fill operation must either
 * exactly overlap or directly abut pixels touched by the
 * corresponding draw operation. A fill operation must never leave
 * a gap between the filled area and the pixels touched by the
 * corresponding draw operation, nor may the fill operation touch
 * pixels outside the area bounded by the corresponding draw operation. </p>
 *
 * <p>
 * <a name="clip"></a>
 * <h3>Clipping</h3> <p>
 *
 * <p>
 * The clip is the set of pixels in the destination of the
 * <code>Graphics</code> object that may be modified by graphics rendering
 * operations.
 *
 * <p>
 * There is a single clip per <code>Graphics</code> object.
 * The only pixels modified by graphics operations are those that lie within the
 * clip. Pixels outside the clip are not modified by any graphics operations.
 *
 * <p>
 * Operations are provided for intersecting the current clip with
 * a given rectangle and for setting the current clip outright.
 * The application may specify the clip by supplying a clip rectangle
 * using coordinates relative to the current coordinate system.
 *
 * <p>
 * It is legal to specify a clip rectangle whose width or height is zero
 * or negative. In this case the clip is considered to be empty,
 * that is, no pixels are contained within it.
 * Therefore, if any graphics operations are issued under such a clip,
 * no pixels will be modified.
 *
 * <p>
 * It is legal to specify a clip rectangle that extends beyond or resides
 * entirely beyond the bounds of the destination.  No pixels exist outside
 * the bounds of the destination, and the area of the clip rectangle
 * that is outside the destination is ignored.  Only the pixels that lie
 * both within the destination and within the specified clip rectangle
 * are considered to be part of the clip.
 *
 * <p>
 * Operations on the coordinate system,
 * such as {@link Graphics#translate(int, int) translate()},
 * do not modify the clip.
 * The methods
 * {@link Graphics#getClipX() getClipX()},
 * {@link Graphics#getClipY() getClipY()},
 * {@link Graphics#getClipWidth() getClipWidth()} and
 * {@link Graphics#getClipHeight() getClipHeight()}
 * must return a rectangle that,
 * if passed to <code>setClip</code> without an intervening change to
 * the <code>Graphics</code> object's coordinate system, must result in
 * the identical set of pixels in the clip.
 * The rectangle returned from the <code>getClip</code> family of methods
 * may differ from the clip rectangle that was requested in
 * {@link Graphics#setClip(int, int, int, int) setClip()}.
 * This can occur if the coordinate system has been changed or if
 * the implementation has chosen to intersect the clip rectangle
 * with the bounds of the destination of the <code>Graphics</code> object.
 *
 * <p>
 * If a graphics operation is affected by the clip, the pixels
 * touched by that operation must be the same ones that would be touched
 * as if the clip did not affect the operation. For example,
 * consider a clip represented by the rectangle <code>(cx, cy, cw, ch)</code>
 * and a point <code>(x1, y1)</code> that
 * lies outside this rectangle and a point <code>(x2, y2)</code>
 * that lies within this
 * rectangle. In the following code fragment, </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.setClip(0, 0, canvas.getWidth(),
 *                    canvas.getHeight());
 *    g.drawLine(x1, y1, x2, y2); // 3
 *    g.setClip(cx, cy, cw, ch);
 *    g.drawLine(x1, y1, x2, y2); // 4     </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <P>
 * The pixels touched by statement (4) must be identical to the pixels
 * within <code>(cx, cy, cw, ch)</code> touched by statement (3). </p>
 * <p>
 * <a name="anchor"></a>
 * <h3>Anchor Points</h3> <p>
 *
 * The drawing of text is based on "anchor points".
 * Anchor points are used to minimize the amount of
 * computation required when placing text.
 * For example, in order to center a piece of text,
 * an application needs to call <code>stringWidth()</code> or
 * <code>charWidth()</code> to get the width and then perform a
 * combination of subtraction and division to
 * compute the proper location.
 * The method to draw text is defined as follows:
 * <pre><code>
 * public void drawString(String text, int x, int y, int anchor);
 * </code></pre>
 * This method draws text in the current color,
 * using the current font
 * with its anchor point at <code>(x,y)</code>. The definition
 * of the anchor point must be one of the
 * horizontal constants <code>(LEFT, HCENTER, RIGHT)</code>
 * combined with one of the vertical constants
 * <code>(TOP, BASELINE, BOTTOM)</code> using the bit-wise
 * <code>OR</code> operator.
 * Zero may also be used as the value of an anchor point.
 * Using zero for the anchor point value gives results
 * identical to using <code>TOP | LEFT</code>.</p>
 *
 * <p>
 * Vertical centering of the text is not specified since it is not considered
 * useful, it is hard to specify, and it is burdensome to implement. Thus,
 * the <code>VCENTER</code> value is not allowed in the anchor point
 * parameter of text
 * drawing calls. </p>
 * <p>
 * The actual position of the bounding box
 * of the text relative to the <code>(x, y)</code> location is
 * determined by the anchor point. These anchor
 * points occur at named locations along the
 * outer edge of the bounding box. Thus, if <code>f</code>
 * is <code>g</code>'s current font (as returned by
 * <code>g.getFont()</code>, the following calls will all have
 * identical results: </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.drawString(str, x, y, TOP|LEFT);
 *    g.drawString(str, x + f.stringWidth(str)/2, y, TOP|HCENTER);
 *    g.drawString(str, x + f.stringWidth(str), y, TOP|RIGHT);
 *
 *    g.drawString(str, x,
 *        y + f.getBaselinePosition(), BASELINE|LEFT);
 *    g.drawString(str, x + f.stringWidth(str)/2,
 *        y + f.getBaselinePosition(), BASELINE|HCENTER);
 *    g.drawString(str, x + f.stringWidth(str),
 *        y + f.getBaselinePosition(), BASELINE|RIGHT);
 *
 *    drawString(str, x,
 *        y + f.getHeight(), BOTTOM|LEFT);
 *    drawString(str, x + f.stringWidth(str)/2,
 *        y + f.getHeight(), BOTTOM|HCENTER);
 *    drawString(str, x + f.stringWidth(str),
 *        y + f.getHeight(), BOTTOM|RIGHT);      </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <p>
 * For text drawing, the inter-character and inter-line spacing (leading)
 * specified by the font designer are included as part of the values returned
 * in the {@link Font#stringWidth(java.lang.String) stringWidth()}
 * and {@link Font#getHeight() getHeight()}
 * calls of class {@link Font Font}.
 * For example, given the following code: </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    // (5)
 *    g.drawString(string1+string2, x, y, TOP|LEFT);
 *
 *    // (6)
 *    g.drawString(string1, x, y, TOP|LEFT);
 *    g.drawString(string2, x + f.stringWidth(string1), y, TOP|LEFT);     </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * </P>
 * <P>
 * Code fragments (5) and (6) behave similarly if not identically. This
 * occurs because <code>f.stringWidth()</code>
 * includes the inter-character spacing.  The exact spacing of may differ
 * between these calls if the system supports font kerning.</p>
 *
 * <p>Similarly, reasonable vertical spacing may be
 * achieved simply by adding the font height
 * to the Y-position of subsequent lines. For example: </P>
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g.drawString(string1, x, y, TOP|LEFT);
 *    g.drawString(string2, x, y + f.fontHeight(), TOP|LEFT);    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <P>
 * draws <code>string1</code> and <code>string2</code> on separate lines with
 * an appropriate amount of inter-line spacing. </p>
 * <p>
 * The <code>stringWidth()</code> of the string and the
 * <code>fontHeight()</code> of the font in which
 * it is drawn define the size of the bounding box of a piece of text. As
 * described above, this box includes inter-line and inter-character spacing.
 * The implementation is required to put this space below and to right of the
 * pixels actually belonging to the characters drawn. Applications that wish
 * to position graphics closely with respect to text (for example, to paint a
 * rectangle around a string of text) may assume that there is space below and
 * to the right of a string and that there is <em>no</em> space above
 * and to the
 * left of the string. </p>
 * <p>
 * Anchor points are also used for positioning of images. Similar to text
 * drawing, the anchor point for an image specifies the point on the bounding
 * rectangle of the destination that is to positioned at the
 * <code>(x,y)</code> location
 * given in the graphics request. Unlike text, vertical centering of images
 * is well-defined, and thus the <code>VCENTER</code> value may be
 * used within the anchor
 * point parameter of image drawing requests. Because images have no notion
 * of a baseline, the <code>BASELINE</code> value may not be used
 * within the anchor point
 * parameter of image drawing requests. </p>
 *
 * <h3>Reference</h3>
 *
 * <dl>
 * <dt>Porter-Duff
 * <dd>Porter, T., and T. Duff.  "Compositing Digital Images."
 * <em>Computer Graphics V18 N3 (SIGGRAPH 1984)</em>, p. 253-259.
 * </dl>
 *
 * @since MIDP 1.0
 */

public class Graphics {

    // SYNC NOTE: the main Graphics class is entirely unlocked.  There is only
    // one instance of Graphics (created in Display) and it is only ever legal
    // for the application to use it when the system calls the paint() method
    // of a Canvas.  Since paint() calls are serialized, and these methods
    // modify only instance state, no locking is necessary.  (If any method
    // were to read or modify global state, locking would need to be done in
    // those cases.)

    /**
     * Constant for centering text and images horizontally
     * around the anchor point
     *
     * <P>Value <code>1</code> is assigned to <code>HCENTER</code>.</P>
     */
    public static final int HCENTER = 1;
  
    /**
     * Constant for centering images vertically
     * around the anchor point.
     *
     * <P>Value <code>2</code> is assigned to <code>VCENTER</code>.</P>
     */
    public static final int VCENTER = 2;
  
    /**
     * Constant for positioning the anchor point of text and images
     * to the left of the text or image.
     *
     * <P>Value <code>4</code> is assigned to <code>LEFT</code>.</P>
     */
    public static final int LEFT = 4;
  
    /**
     * Constant for positioning the anchor point of text and images
     * to the right of the text or image.
     *
     * <P>Value <code>8</code> is assigned to <code>RIGHT</code>.</P>
     */
    public static final int RIGHT = 8;
  
    /**
     * Constant for positioning the anchor point of text and images
     * above the text or image.
     *
     * <P>Value <code>16</code> is assigned to <code>TOP</code>.</P>
     */
    public static final int TOP = 16;
  
    /**
     * Constant for positioning the anchor point of text and images
     * below the text or image.
     *
     * <P>Value <code>32</code> is assigned to <code>BOTTOM</code>.</P>
     */
    public static final int BOTTOM = 32;
  
    /**
     * Constant for positioning the anchor point at the baseline of text.
     *
     * <P>Value <code>64</code> is assigned to <code>BASELINE</code>.</P>
     */
    public static final int BASELINE = 64;

    /**
     * Constant for the <code>SOLID</code> stroke style.
     *
     * <P>Value <code>0</code> is assigned to <code>SOLID</code>.</P>
     */
    public static final int SOLID = 0;

    /**
     * Constant for the <code>DOTTED</code> stroke style.
     *
     * <P>Value <code>1</code> is assigned to <code>DOTTED</code>.</P>
     */
    public static final int DOTTED = 1;

    /**
     * Intialize the native peer of this Graphics context
     */
    private native void init();

    /**
     * Create a Graphics object with the given width and height
     *
     * @param w The maximum width of the new Graphics object
     * @param h The maximum height of the new Graphics object
     */
    Graphics(int w, int h) {
        destination = null;

        maxWidth  = (short) (w & 0x7fff);
        maxHeight = (short) (h & 0x7fff);

        init();
        reset();
    }

    /**
     * Translates the origin of the graphics context to the point
     * <code>(x, y)</code> in the current coordinate system. All coordinates
     * used in subsequent rendering operations on this graphics
     * context will be relative to this new origin.<p>
     *
     * The effect of calls to <code>translate()</code> are
     * cumulative. For example, calling
     * <code>translate(1, 2)</code> and then <code>translate(3,
     * 4)</code> results in a translation of
     * <code>(4, 6)</code>. <p>
     *
     * The application can set an absolute origin <code>(ax,
     * ay)</code> using the following
     * technique:<p>
     * <code>
     * g.translate(ax - g.getTranslateX(), ay - g.getTranslateY())
     * </code><p>
     *
     * @param x the x coordinate of the new translation origin
     * @param y the y coordinate of the new translation origin
     * @see #getTranslateX()
     * @see #getTranslateY()
     */
    public void translate(int x, int y) {
        transX += x;
        transY += y;
    }

    /**
     * Gets the X coordinate of the translated origin of this graphics context.
     * @return X of current origin
     */
    public int getTranslateX() {
        return transX;
    }

    /**
     * Gets the Y coordinate of the translated origin of this graphics context.
     * @return Y of current origin
     */
    public int getTranslateY() {
        return transY;
    }

    /**
     * Gets the current color.
     * @return an integer in form <code>0x00RRGGBB</code>
     * @see #setColor(int, int, int)
     */
    public int getColor() {
        return rgbColor;
    }

    /**
     * Gets the red component of the current color.
     * @return integer value in range <code>0-255</code>
     * @see #setColor(int, int, int)
     */
    public int getRedComponent() {
        return (rgbColor >> 16) & 0xff;
    }

    /**
     * Gets the green component of the current color.
     * @return integer value in range <code>0-255</code>
     * @see #setColor(int, int, int)
     */
    public int getGreenComponent() {
        return (rgbColor >> 8) & 0xff;
    }

    /**
     * Gets the blue component of the current color.
     * @return integer value in range <code>0-255</code>
     * @see #setColor(int, int, int)
     */
    public int getBlueComponent() {
        return rgbColor & 0xff;
    }

    /**
     * Gets the current grayscale value of the color being used for rendering
     * operations. If the color was set by
     * <code>setGrayScale()</code>, that value is simply
     * returned. If the color was set by one of the methods that allows setting
     * of the red, green, and blue components, the value returned is 
     * computed from
     * the RGB color components (possibly in a device-specific fashion)
     * that best
     * approximates the brightness of that color.
     *
     * @return integer value in range <code>0-255</code>
     * @see #setGrayScale
     */
    public int getGrayScale() {
        return gray;
    }

    /**
     * Sets the current color to the specified RGB values. All subsequent
     * rendering operations will use this specified color.
     * @param red the red component of the color being set in range
     * <code>0-255</code>
     * @param green the green component of the color being set in range
     * <code>0-255</code>
     * @param blue the blue component of the color being set in range
     * <code>0-255</code>
     * @throws IllegalArgumentException if any of the color components
     * are outside of range <code>0-255</code>
     * @see #getColor
     */
    public void setColor(int red, int green, int blue) {
        if ((red < 0)   || (red > 255) 
            || (green < 0) || (green > 255)
            || (blue < 0)  || (blue > 255)) {
            throw new IllegalArgumentException("Value out of range");
        }

        rgbColor = (red << 16) | (green << 8) | blue;
        gray = grayVal(red, green, blue);
        pixel = getPixel(rgbColor, gray, false);
    }

    /**
     * Sets the current color to the specified RGB values. All subsequent
     * rendering operations will use this specified color. The RGB value
     * passed in is interpreted with the least significant eight bits
     * giving the blue component, the next eight more significant bits
     * giving the green component, and the next eight more significant
     * bits giving the red component. That is to say, the color component
     * is specified in the form of <code>0x00RRGGBB</code>. The high
     * order byte of
     * this value is ignored.
     *
     * @param RGB the color being set
     * @see #getColor
     */
    public void setColor(int RGB) {
        int red   = (RGB >> 16) & 0xff;
        int green = (RGB >> 8)  & 0xff;
        int blue  = (RGB)  & 0xff;

        rgbColor = RGB & 0x00ffffff;
        gray = grayVal(red, green, blue);
        pixel = getPixel(rgbColor, gray, false);
    }

    /**
     * Sets the current grayscale to be used for all subsequent
     * rendering operations. For monochrome displays, the behavior
     * is clear. For color displays, this sets the color for all
     * subsequent drawing operations to be a gray color equivalent
     * to the value passed in. The value must be in the range
     * <code>0-255</code>.
     * @param value the desired grayscale value
     * @throws IllegalArgumentException if the gray value is out of range
     * @see #getGrayScale
     */
    public void setGrayScale(int value) {
        if ((value < 0) || (value > 255)) {
            throw new IllegalArgumentException("Gray value out of range");
        }

        rgbColor = (value << 16) | (value << 8) | value;
        gray = value;
        pixel = getPixel(rgbColor, gray, true);
    }

    /**
     * Gets the current font.
     * @return current font
     * @see javax.microedition.lcdui.Font
     * @see #setFont(javax.microedition.lcdui.Font)
     */
    public Font getFont() {
        return currentFont;
    }

    /**
     * Sets the stroke style used for drawing lines, arcs, rectangles, and 
     * rounded rectangles.  This does not affect fill, text, and image 
     * operations.
     * @param style can be <code>SOLID</code> or <code>DOTTED</code>
     * @throws IllegalArgumentException if the <code>style</code> is illegal
     * @see #getStrokeStyle
     */
    public void setStrokeStyle(int style) {
        if ((style != SOLID) && (style != DOTTED)) {
            throw new IllegalArgumentException("Invalid line style");
        }

        this.style = style;
    }

    /**
     * Gets the stroke style used for drawing operations.
     * @return stroke style, <code>SOLID</code> or <code>DOTTED</code>
     * @see #setStrokeStyle
     */
    public int getStrokeStyle() {
        return style;
    }

    /**
     * Sets the font for all subsequent text rendering operations.  If font is 
     * <code>null</code>, it is equivalent to
     * <code>setFont(Font.getDefaultFont())</code>.
     * 
     * @param font the specified font
     * @see javax.microedition.lcdui.Font
     * @see #getFont()
     * @see #drawString(java.lang.String, int, int, int)
     * @see #drawChars(char[], int, int, int, int, int)
     */
    public void setFont(Font font) {
        currentFont = (font == null) ? Font.getDefaultFont() : font;
    }
  
    /**
     * Gets the X offset of the current clipping area, relative
     * to the coordinate system origin of this graphics context.
     * Separating the <code>getClip</code> operation into two methods returning
     * integers is more performance and memory efficient than one
     * <code>getClip()</code> call returning an object.
     * @return X offset of the current clipping area
     * @see #clipRect(int, int, int, int)
     * @see #setClip(int, int, int, int)
     */
    public int getClipX() {
        return clip[0] - transX;
    }

    /**
     * Gets the Y offset of the current clipping area, relative
     * to the coordinate system origin of this graphics context.
     * Separating the <code>getClip</code> operation into two methods returning
     * integers is more performance and memory efficient than one
     * <code>getClip()</code> call returning an object.
     * @return Y offset of the current clipping area
     * @see #clipRect(int, int, int, int)
     * @see #setClip(int, int, int, int)
     */
    public int getClipY() {
        return clip[1] - transY;
    }

    /**
     * Gets the width of the current clipping area.
     * @return width of the current clipping area.
     * @see #clipRect(int, int, int, int)
     * @see #setClip(int, int, int, int)
     */
    public int getClipWidth() {
        return clip[2];
    }


    /**
     * Gets the height of the current clipping area.
     * @return height of the current clipping area.
     * @see #clipRect(int, int, int, int)
     * @see #setClip(int, int, int, int)
     */
    public int getClipHeight()	{
        return clip[3];
    }

    /**
     * Intersects the current clip with the specified rectangle.
     * The resulting clipping area is the intersection of the current
     * clipping area and the specified rectangle.
     * This method can only be used to make the current clip smaller.
     * To set the current clip larger, use the <code>setClip</code> method.
     * Rendering operations have no effect outside of the clipping area.
     * @param x the x coordinate of the rectangle to intersect the clip with
     * @param y the y coordinate of the rectangle to intersect the clip with
     * @param width the width of the rectangle to intersect the clip with
     * @param height the height of the rectangle to intersect the clip with
     * @see #setClip(int, int, int, int)
     */
    public void clipRect(int x, int y, int width, int height) {

        // If the passed in rect's width/height 
        // is 0 or < 0 then set to zero and return
        if (width <= 0 || height  <= 0) {
            // no pixels should be in clip 
            clip[2] = 0;
            clip[3] = 0;
            clipped = true;
            return;
        }

        translatedX1 = x + transX;
        translatedY1 = y + transY;

        if (translatedX1 < 0) {
            translatedX1 = (x < 0 || transX < 0) ? 0 : maxWidth;
        }

        if (translatedY1 < 0) {
            translatedY1 = (y < 0 || transY < 0) ? 0 : maxHeight;
        }

        /*
        * short values are safe because we guarantee positive numbers
        * and a width and height which don't exceed the displayable area.
        */

        clipX2 = clip[0] + clip[2];
        clipY2 = clip[1] + clip[3];

        // If the passed in rect is below our current clip
        if (clipX2 < translatedX1 || clipY2 < translatedY1) {
            // we have no intersection
            clip[2] = 0;
            clip[3] = 0;
            clipped = true;
            return;
        }

        if (translatedX1 > clip[0]) {
            clip[0] = (short) (translatedX1 & 0x7fff);
            clipped = true;
        }

        if (translatedY1 > clip[1]) {
            clip[1] = (short) (translatedY1 & 0x7fff);
            clipped = true;
        }

        // bottom right

        translatedX2 = x + transX + width;
        translatedY2 = y + transY + height;

        if (translatedX2 < 0) {
            translatedX2 = (x < 0 || transX < 0) ? 0 : maxWidth;
        }

        if (translatedY2 < 0) {
            translatedY2 = (y < 0 || transY < 0) ? 0 : maxHeight;
        }

        // If the passed in rect is above our current clip
        if (translatedX2 < clip[0] || translatedY2 < clip[1]) {
            // we have no intersection
            clip[2] = 0;
            clip[3] = 0;
            clipped = true;
            return;
        }

        if (translatedX2 <= clipX2) {
            clipX2 = translatedX2;
            clipped = true;
        }

        if (translatedY2 <= clipY2) {
            clipY2 = translatedY2;
            clipped = true;
        }

	if (clipped == true) {
	    clipX2 -= clip[0];
	    clipY2 -= clip[1];

            clip[2] = (clipX2 > 0) ? 
                      ((short) (clipX2 & 0x7fff)) : 0;
            clip[3] = (clipY2 > 0) ? 
		      ((short) (clipY2 & 0x7fff)) : 0;
	}

    }

    /**
     * Sets the current clip to the rectangle specified by the
     * given coordinates.
     * Rendering operations have no effect outside of the clipping area.
     * @param x the x coordinate of the new clip rectangle
     * @param y the y coordinate of the new clip rectangle
     * @param width the width of the new clip rectangle
     * @param height the height of the new clip rectangle
     * @see #clipRect(int, int, int, int)
     */
    public void setClip(int x, int y, int width, int height) {

        if ((width <= 0) || (height <= 0)) {
            clip[0] = clip[1] = clip[2] = clip[3] = 0;
            clipped = true;
            return;
        }

        translatedX1 = x + transX;
        translatedY1 = y + transY;

        if (translatedX1 < 0) {
            translatedX1 = (x < 0 || transX < 0) ? 0 : maxWidth;
        }

        if (translatedY1 < 0) {
            translatedY1 = (y < 0 || transY < 0) ? 0 : maxHeight;
        }

        clipX1 = (short)(translatedX1 & 0x7fff);
        clipY1 = (short)(translatedY1 & 0x7fff);

        if ((translatedX1 >= maxWidth) 
	    || (translatedY1 >= maxHeight)) {
            clip[0] = clip[1] = clip[2] = clip[3] = 0;
            clipped = true;
            return;
        }

        // safe because we already guaranteed values are small positive
        clip[0] = clipX1;
        clip[1] = clipY1;

        translatedX2 = x + transX + width;
        translatedY2 = y + transY + height;

        if (translatedX2 < 0) {
            translatedX2 = (x < 0 || transX < 0) ? 0 : maxWidth;
        }

        if (translatedY2 < 0) {
            translatedY2 = (y < 0 || transY < 0) ? 0 : maxHeight;
        }

        clip[2] = (short) ((translatedX2 - clipX1) & 0x7fff);
        clip[3] = (short) ((translatedY2 - clipY1) & 0x7fff);

        if (clip[2] > maxWidth) {
            clip[2] = maxWidth;
        }

        if (clip[3] > maxHeight) {
            clip[3] = maxHeight;
        }

        if ((clip[0] > 0) || (clip[1] > 0)
                || (clip[2] < maxWidth) || (clip[3] < maxHeight)) {
            clipped = true;
        }
    }

    /**
     * Draws a line between the coordinates <code>(x1,y1)</code> and
     * <code>(x2,y2)</code> using
     * the current color and stroke style.
     * @param x1 the x coordinate of the start of the line
     * @param y1 the y coordinate of the start of the line
     * @param x2 the x coordinate of the end of the line
     * @param y2 the y coordinate of the end of the line
     */
    public native void drawLine(int x1, int y1, int x2, int y2);

    /**
     * Fills the specified rectangle with the current color.
     * If either width or height is zero or less,
     * nothing is drawn.
     * @param x the x coordinate of the rectangle to be filled
     * @param y the y coordinate of the rectangle to be filled
     * @param width the width of the rectangle to be filled
     * @param height the height of the rectangle to be filled
     * @see #drawRect(int, int, int, int)
     */
    public native void fillRect(int x, int y, int width, int height);
 
    /**
     * Draws the outline of the specified rectangle using the current
     * color and stroke style.
     * The resulting rectangle will cover an area <code>(width + 1)</code>
     * pixels wide by <code>(height + 1)</code> pixels tall.
     * If either width or height is less than
     * zero, nothing is drawn.
     * @param x the x coordinate of the rectangle to be drawn
     * @param y the y coordinate of the rectangle to be drawn
     * @param width the width of the rectangle to be drawn
     * @param height the height of the rectangle to be drawn
     * @see #fillRect(int, int, int, int)
     */
    public native void drawRect(int x, int y, int width, int height);

    /**
     * Draws the outline of the specified rounded corner rectangle
     * using the current color and stroke style.
     * The resulting rectangle will cover an area <code>(width +
     * 1)</code> pixels wide
     * by <code>(height + 1)</code> pixels tall.
     * If either <code>width</code> or <code>height</code> is less than
     * zero, nothing is drawn.
     * @param x the x coordinate of the rectangle to be drawn
     * @param y the y coordinate of the rectangle to be drawn
     * @param width the width of the rectangle to be drawn
     * @param height the height of the rectangle to be drawn
     * @param arcWidth the horizontal diameter of the arc at the four corners
     * @param arcHeight the vertical diameter of the arc at the four corners
     * @see #fillRoundRect(int, int, int, int, int, int)
     */
    public native void drawRoundRect(int x, int y, int width, int height,
                                     int arcWidth, int arcHeight);
 
    /**
     * Fills the specified rounded corner rectangle with the current color.
     * If either <code>width</code> or <code>height</code> is zero or less,
     * nothing is drawn.
     * @param x the x coordinate of the rectangle to be filled
     * @param y the y coordinate of the rectangle to be filled
     * @param width the width of the rectangle to be filled
     * @param height the height of the rectangle to be filled
     * @param arcWidth the horizontal diameter of the arc at the four
     * corners
     * @param arcHeight the vertical diameter of the arc at the four corners
     * @see #drawRoundRect(int, int, int, int, int, int)
     */
    public native void fillRoundRect(int x, int y, int width, int height,
                                     int arcWidth, int arcHeight);
                          
    /**
     * Fills a circular or elliptical arc covering the specified rectangle.
     * <p>
     * The resulting arc begins at <code>startAngle</code> and extends
     * for <code>arcAngle</code> degrees.
     * Angles are interpreted such that <code>0</code> degrees
     * is at the <code>3</code> o'clock position.
     * A positive value indicates a counter-clockwise rotation
     * while a negative value indicates a clockwise rotation.
     * <p>
     * The center of the arc is the center of the rectangle whose origin
     * is (<em>x</em>, <em>y</em>) and whose size is specified by the
     * <code>width</code> and <code>height</code> arguments.
     * <p>
     * If either <code>width</code> or <code>height</code> is zero or less,
     * nothing is drawn.
     *
     * <p> The filled region consists of the "pie wedge"
     * region bounded
     * by the arc
     * segment as if drawn by <code>drawArc()</code>, the radius extending from
     * the center to
     * this arc at <code>startAngle</code> degrees, and radius extending
     * from the
     * center to this arc at <code>startAngle + arcAngle</code> degrees. </p>
     *
     * <p> The angles are specified relative to the non-square extents of
     * the bounding rectangle such that <code>45</code> degrees always
     * falls on the
     * line from the center of the ellipse to the upper right corner of
     * the bounding rectangle. As a result, if the bounding rectangle is
     * noticeably longer in one axis than the other, the angles to the
     * start and end of the arc segment will be skewed farther along the
     * longer axis of the bounds. </p>
     *
     * @param x the <em>x</em> coordinate of the upper-left corner of
     * the arc to be filled.
     * @param y the <em>y</em> coordinate of the upper-left corner of the
     * arc to be filled.
     * @param width the width of the arc to be filled
     * @param height the height of the arc to be filled
     * @param startAngle the beginning angle.
     * @param arcAngle the angular extent of the arc,
     * relative to the start angle.
     * @see #drawArc(int, int, int, int, int, int)
     */
    public native void fillArc(int x, int y, int width, int height,
                               int startAngle, int arcAngle);

    /**
     * Draws the outline of a circular or elliptical arc
     * covering the specified rectangle,
     * using the current color and stroke style.
     * <p>
     * The resulting arc begins at <code>startAngle</code> and extends
     * for <code>arcAngle</code> degrees, using the current color.
     * Angles are interpreted such that <code>0</code> degrees
     * is at the <code>3</code> o'clock position.
     * A positive value indicates a counter-clockwise rotation
     * while a negative value indicates a clockwise rotation.
     * <p>
     * The center of the arc is the center of the rectangle whose origin
     * is (<em>x</em>, <em>y</em>) and whose size is specified by the
     * <code>width</code> and <code>height</code> arguments.
     * <p>
     * The resulting arc covers an area
     * <code>width + 1</code> pixels wide
     * by <code>height + 1</code> pixels tall.
     * If either <code>width</code> or <code>height</code> is less than zero,
     * nothing is drawn.
     *
     * <p> The angles are specified relative to the non-square extents of
     * the bounding rectangle such that <code>45</code> degrees always
     * falls on the
     * line from the center of the ellipse to the upper right corner of
     * the bounding rectangle. As a result, if the bounding rectangle is
     * noticeably longer in one axis than the other, the angles to the
     * start and end of the arc segment will be skewed farther along the
     * longer axis of the bounds. </p>
     *
     * @param x the <em>x</em> coordinate of the upper-left corner
     * of the arc to be drawn
     * @param y the <em>y</em> coordinate of the upper-left corner
     * of the arc to be drawn
     * @param width the width of the arc to be drawn
     * @param height the height of the arc to be drawn
     * @param startAngle the beginning angle
     * @param arcAngle the angular extent of the arc, relative to
     * the start angle
     * @see #fillArc(int, int, int, int, int, int)
     */
    public native void drawArc(int x, int y, int width, int height,
                               int startAngle, int arcAngle);

    /**
     * Draws the specified <code>String</code> using the current font and color.
     * The <code>x,y</code> position is the position of the anchor point.
     * See <a href="#anchor">anchor points</a>.
     * @param str the <code>String</code> to be drawn
     * @param x the x coordinate of the anchor point
     * @param y the y coordinate of the anchor point
     * @param anchor the anchor point for positioning the text
     * @throws NullPointerException if <code>str</code> is <code>null</code>
     * @throws IllegalArgumentException if anchor is not a legal value
     * @see #drawChars(char[], int, int, int, int, int)
     */
    public native void drawString(java.lang.String str,
                                  int x, int y, int anchor);

    /**
     * Draws the specified <code>String</code> using the current font and color.
     * The <code>x,y</code> position is the position of the anchor point.
     * See <a href="#anchor">anchor points</a>.
     *
     * <p>The <code>offset</code> and <code>len</code> parameters must
     * specify a valid range of characters within
     * the string <code>str</code>.
     * The <code>offset</code> parameter must be within the
     * range <code>[0..(str.length())]</code>, inclusive.
     * The <code>len</code> parameter
     * must be a non-negative integer such that
     * <code>(offset + len) <= str.length()</code>.</p>
     *
     * @param str the <code>String</code> to be drawn
     * @param offset zero-based index of first character in the substring
     * @param len length of the substring
     * @param x the x coordinate of the anchor point
     * @param y the y coordinate of the anchor point
     * @param anchor the anchor point for positioning the text
     * @see #drawString(String, int, int, int).
     * @throws StringIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code> do not specify
     * a valid range within the <code>String</code> <code>str</code>
     * @throws IllegalArgumentException if <code>anchor</code>
     * is not a legal value
     * @throws NullPointerException if <code>str</code> is <code>null</code>
     */
    public native void drawSubstring(String str, int offset, int len,
                                     int x, int y, int anchor);

    /**
     * Draws the specified character using the current font and color.
     * @param character the character to be drawn
     * @param x the x coordinate of the anchor point
     * @param y the y coordinate of the anchor point
     * @param anchor the anchor point for positioning the text; see
     * <a href="#anchor">anchor points</a>
     *
     * @throws IllegalArgumentException if <code>anchor</code>
     * is not a legal value
     *
     * @see #drawString(java.lang.String, int, int, int)
     * @see #drawChars(char[], int, int, int, int, int)
     */
    public native void drawChar(char character, int x, int y, int anchor);

    /**
     * Draws the specified characters using the current font and color.
     *
     * <p>The <code>offset</code> and <code>length</code> parameters must
     * specify a valid range of characters within
     * the character array <code>data</code>.
     * The <code>offset</code> parameter must be within the
     * range <code>[0..(data.length)]</code>, inclusive.
     * The <code>length</code> parameter
     * must be a non-negative integer such that
     * <code>(offset + length) <= data.length</code>.</p>
     *
     * @param data the array of characters to be drawn
     * @param offset the start offset in the data
     * @param length the number of characters to be drawn
     * @param x the x coordinate of the anchor point
     * @param y the y coordinate of the anchor point
     * @param anchor the anchor point for positioning the text; see
     * <a href="#anchor">anchor points</a>
     *
     * @throws ArrayIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code>
     * do not specify a valid range within the data array
     * @throws IllegalArgumentException if anchor is not a legal value
     * @throws NullPointerException if <code>data</code> is <code>null</code>
     *
     * @see #drawString(java.lang.String, int, int, int)
     */
    public native void drawChars(char[] data, int offset, int length,
                                 int x, int y, int anchor);
 
    /**
     * Draws the specified image by using the anchor point.
     * The image can be drawn in different positions relative to
     * the anchor point by passing the appropriate position constants.
     * See <a href="#anchor">anchor points</a>.
     *
     * <p>If the source image contains transparent pixels, the corresponding
     * pixels in the destination image must be left untouched.  If the source
     * image contains partially transparent pixels, a compositing operation 
     * must be performed with the destination pixels, leaving all pixels of 
     * the destination image fully opaque.</p>
     *
     * <p>If <code>img</code> is the same as the destination of this Graphics
     * object, the result is undefined.  For copying areas within an
     * <code>Image</code>, {@link #copyArea copyArea} should be used instead.
     * </p>
     *
     * @param img the specified image to be drawn
     * @param x the x coordinate of the anchor point
     * @param y the y coordinate of the anchor point
     * @param anchor the anchor point for positioning the image
     * @throws IllegalArgumentException if <code>anchor</code>
     * is not a legal value
     * @throws NullPointerException if <code>img</code> is <code>null</code>
     * @see Image
     */
    public native void drawImage(Image img, int x, int y, int anchor);

    /**
     * Copies a region of the specified source image to a location within
     * the destination, possibly transforming (rotating and reflecting)
     * the image data using the chosen transform function.
     *
     * <p>The destination, if it is an image, must not be the same image as
     * the source image.  If it is, an exception is thrown.  This restriction
     * is present in order to avoid ill-defined behaviors that might occur if
     * overlapped, transformed copies were permitted.</p>
     *
     * <p>The transform function used must be one of the following, as defined
     * in the {@link javax.microedition.lcdui.game.Sprite Sprite} class:<br>
     *
     * <code>Sprite.TRANS_NONE</code> - causes the specified image
     * region to be copied unchanged<br>
     * <code>Sprite.TRANS_ROT90</code> - causes the specified image
     * region to be rotated clockwise by 90 degrees.<br>
     * <code>Sprite.TRANS_ROT180</code> - causes the specified image
     * region to be rotated clockwise by 180 degrees.<br>
     * <code>Sprite.TRANS_ROT270</code> - causes the specified image
     * region to be rotated clockwise by 270 degrees.<br>
     * <code>Sprite.TRANS_MIRROR</code> - causes the specified image
     * region to be reflected about its vertical center.<br>
     * <code>Sprite.TRANS_MIRROR_ROT90</code> - causes the specified image
     * region to be reflected about its vertical center and then rotated
     * clockwise by 90 degrees.<br>
     * <code>Sprite.TRANS_MIRROR_ROT180</code> - causes the specified image
     * region to be reflected about its vertical center and then rotated
     * clockwise by 180 degrees.<br>
     * <code>Sprite.TRANS_MIRROR_ROT270</code> - causes the specified image
     * region to be reflected about its vertical center and then rotated
     * clockwise by 270 degrees.<br></p>
     *
     * <p>If the source region contains transparent pixels, the corresponding
     * pixels in the destination region must be left untouched.  If the source
     * region contains partially transparent pixels, a compositing operation
     * must be performed with the destination pixels, leaving all pixels of
     * the destination region fully opaque.</p>
     *
     * <p> The <code>(x_src, y_src)</code> coordinates are relative to
     * the upper left
     * corner of the source image.  The <code>x_src</code>,
     * <code>y_src</code>, <code>width</code>, and <code>height</code>
     * parameters specify a rectangular region of the source image.  It is
     * illegal for this region to extend beyond the bounds of the source
     * image.  This requires that: </P>
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *   x_src >= 0
     *   y_src >= 0
     *   x_src + width <= source width
     *   y_src + height <= source height    </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     * <P>
     * The <code>(x_dest, y_dest)</code> coordinates are relative to
     * the coordinate
     * system of this Graphics object.  It is legal for the destination
     * area to extend beyond the bounds of the <code>Graphics</code>
     * object.  Pixels
     * outside of the bounds of the <code>Graphics</code> object will
     * not be drawn.</p>
     *
     * <p>The transform is applied to the image data from the region of the
     * source image, and the result is rendered with its anchor point
     * positioned at location <code>(x_dest, y_dest)</code> in the
     * destination.</p>
     *
     * @param src the source image to copy from
     * @param x_src the x coordinate of the upper left corner of the region
     * within the source image to copy
     * @param y_src the y coordinate of the upper left corner of the region
     * within the source image to copy
     * @param width the width of the region to copy
     * @param height the height of the region to copy
     * @param transform the desired transformation for the selected region
     * being copied
     * @param x_dest the x coordinate of the anchor point in the
     * destination drawing area
     * @param y_dest the y coordinate of the anchor point in the
     * destination drawing area
     * @param anchor the anchor point for positioning the region within
     * the destination image
     *
     * @throws IllegalArgumentException if <code>src</code> is the
     * same image as the
     * destination of this <code>Graphics</code> object
     * @throws NullPointerException if <code>src</code> is <code>null</code>
     * @throws IllegalArgumentException if <code>transform</code> is invalid
     * @throws IllegalArgumentException if <code>anchor</code> is invalid
     * @throws IllegalArgumentException if the region to be copied exceeds
     * the bounds of the source image
     * @since MIDP 2.0
     */
    public native void drawRegion(Image src, 
                                  int x_src, int y_src,
                                  int width, int height, 
                                  int transform,
                                  int x_dest, int y_dest, 
                                  int anchor);

    /**
     * Copies the contents of a rectangular area
     * <code>(x_src, y_src, width, height)</code> to a destination area,
     * whose anchor point identified by anchor is located at
     * <code>(x_dest, y_dest)</code>.  The effect must be that the
     * destination area
     * contains an exact copy of the contents of the source area
     * immediately prior to the invocation of this method.  This result must
     * occur even if the source and destination areas overlap.
     *
     * <p>The points <code>(x_src, y_src)</code> and <code>(x_dest,
     * y_dest)</code> are both specified
     * relative to the coordinate system of the <code>Graphics</code>
     * object.  It is
     * illegal for the source region to extend beyond the bounds of the
     * graphic object.  This requires that: </P>
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *   x_src + tx >= 0
     *   y_src + ty >= 0
     *   x_src + tx + width <= width of Graphics object's destination
     *   y_src + ty + height <= height of Graphics object's destination      </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     * 
     * <p>where <code>tx</code> and <code>ty</code> represent the X and Y 
     * coordinates of the translated origin of this graphics object, as 
     * returned by <code>getTranslateX()</code> and
     * <code>getTranslateY()</code>, respectively.</p>
     * 
     * <P>
     * However, it is legal for the destination area to extend beyond
     * the bounds of the <code>Graphics</code> object.  Pixels outside
     * of the bounds of
     * the <code>Graphics</code> object will not be drawn.</p>
     *
     * <p>The <code>copyArea</code> method is allowed on all
     * <code>Graphics</code> objects except those
     * whose destination is the actual display device.  This restriction is
     * necessary because allowing a <code>copyArea</code> method on
     * the display would
     * adversely impact certain techniques for implementing
     * double-buffering.</p>
     *
     * <p>Like other graphics operations, the <code>copyArea</code>
     * method uses the Source
     * Over Destination rule for combining pixels.  However, since it is
     * defined only for mutable images, which can contain only fully opaque
     * pixels, this is effectively the same as pixel replacement.</p>
     *
     * @param x_src  the x coordinate of upper left corner of source area
     * @param y_src  the y coordinate of upper left corner of source area
     * @param width  the width of the source area
     * @param height the height of the source area
     * @param x_dest the x coordinate of the destination anchor point
     * @param y_dest the y coordinate of the destination anchor point
     * @param anchor the anchor point for positioning the region within
     *        the destination image
     *
     * @throws IllegalStateException if the destination of this
     * <code>Graphics</code> object is the display device
     * @throws IllegalArgumentException if the region to be copied exceeds
     * the bounds of the source image
     *
     * @since MIDP 2.0
     */
    public void copyArea(int x_src, int y_src, int width, int height,
			 int x_dest, int y_dest, int anchor) {

	if (Display.isGraphicsDisplay(this)) {
	    throw new IllegalStateException();
	} else {
	    doCopyArea(x_src, y_src, width, height, 
		       x_dest, y_dest, anchor);
	}
    }

    /**
     * Fills the specified triangle will the current color.  The lines
     * connecting each pair of points are included in the filled
     * triangle.
     *
     * @param x1 the x coordinate of the first vertex of the triangle
     * @param y1 the y coordinate of the first vertex of the triangle
     * @param x2 the x coordinate of the second vertex of the triangle
     * @param y2 the y coordinate of the second vertex of the triangle
     * @param x3 the x coordinate of the third vertex of the triangle
     * @param y3 the y coordinate of the third vertex of the triangle
     *
     * @since MIDP 2.0
     */
    public native void fillTriangle(int x1, int y1, 
				    int x2, int y2,
				    int x3, int y3);

    /**
     * Native implementation of CopyArea method.
     *
     * @param x_src  the x coordinate of upper left corner of source area
     * @param y_src  the y coordinate of upper left corner of source area
     * @param width  the width of the source area
     * @param height the height of the source area
     * @param x_dest the x coordinate of the destination anchor point
     * @param y_dest the y coordinate of the destination anchor point
     * @param anchor the anchor point for positioning the region within
     *        the destination image
     *
     * @throws IllegalArgumentException if the region to be copied exceeds
     * the bounds of the source image
     */
    private native void doCopyArea(int x_src, int y_src, 
				   int width, int height, 
				   int x_dest, int y_dest, int anchor);

    /**
     * Renders a series of device-independent RGB+transparency values in a
     * specified region.  The values are stored in
     * <code>rgbData</code> in a format
     * with <code>24</code> bits of RGB and an eight-bit alpha value
     * (<code>0xAARRGGBB</code>),
     * with the first value stored at the specified offset.  The
     * <code>scanlength</code>
     * specifies the relative offset within the array between the
     * corresponding pixels of consecutive rows.  Any value for
     * <code>scanlength</code> is acceptable (even negative values)
     * provided that all resulting references are within the
     * bounds of the <code>rgbData</code> array. The ARGB data is
     * rasterized horizontally from left to right within each row.
     * The ARGB values are
     * rendered in the region specified by <code>x</code>,
     * <code>y</code>, <code>width</code> and <code>height</code>, and
     * the operation is subject to the current clip region
     * and translation for this <code>Graphics</code> object.
     *
     * <p>Consider <code>P(a,b)</code> to be the value of the pixel
     * located at column <code>a</code> and row <code>b</code> of the
     * Image, where rows and columns are numbered downward from the
     * top starting at zero, and columns are numbered rightward from
     * the left starting at zero. This operation can then be defined
     * as:</p>
     *
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *    P(a, b) = rgbData[offset + (a - x) + (b - y) * scanlength]       </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     *
     * <p> for </p>
     *
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *     x <= a < x + width
     *     y <= b < y + height    </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     * <p> This capability is provided in the <code>Graphics</code>
     * class so that it can be
     * used to render both to the screen and to offscreen
     * <code>Image</code> objects.  The
     * ability to retrieve ARGB values is provided by the {@link Image#getRGB}
     * method. </p>
     *
     * <p> If <code>processAlpha</code> is <code>true</code>, the
     * high-order byte of the ARGB format
     * specifies opacity; that is, <code>0x00RRGGBB</code> specifies a
     * fully transparent
     * pixel and <code>0xFFRRGGBB</code> specifies a fully opaque
     * pixel.  Intermediate
     * alpha values specify semitransparency.  If the implementation does not
     * support alpha blending for image rendering operations, it must remove
     * any semitransparency from the source data prior to performing any
     * rendering.  (See <a href="Image.html#alpha">Alpha Processing</a> for
     * further discussion.)
     * If <code>processAlpha</code> is <code>false</code>, the alpha
     * values are ignored and all pixels
     * must be treated as completely opaque.</p>
     *
     * <p> The mapping from ARGB values to the device-dependent
     * pixels is platform-specific and may require significant
     * computation.</p>
     *
     * @param rgbData an array of ARGB values in the format
     * <code>0xAARRGGBB</code>
     * @param offset the array index of the first ARGB value
     * @param scanlength the relative array offset between the
     * corresponding pixels in consecutive rows in the
     * <code>rgbData</code> array
     * @param x the horizontal location of the region to be rendered
     * @param y the vertical location of the region to be rendered
     * @param width the width of the region to be rendered
     * @param height the height of the region to be rendered
     * @param processAlpha <code>true</code> if <code>rgbData</code>
     * has an alpha channel,
     * false if all pixels are fully opaque
     *
     * @throws ArrayIndexOutOfBoundsException if the requested operation
     * will attempt to access an element of <code>rgbData</code>
     * whose index is either negative or beyond its length
     * @throws NullPointerException if <code>rgbData</code> is <code>null</code>
     *
     * @since MIDP 2.0
     */
    public native void drawRGB(int[] rgbData, int offset, int scanlength,
			       int x, int y, int width, int height,
			       boolean processAlpha);

    /**
     * Gets the color that will be displayed if the specified color
     * is requested. This method enables the developer to check the
     * manner in which RGB values are mapped to the set of distinct 
     * colors that the device can actually display. For example, 
     * with a monochrome device, this method will return either
     * <code>0xFFFFFF</code> (white) or <code>0x000000</code> (black) 
     * depending on the brightness of the specified color.
     *
     * @param color the desired color (in <code>0x00RRGGBB</code>
     * format, the high-order
     * byte is ignored)
     * @return the corresponding color that will be displayed on the device's
     * screen (in <code>0x00RRGGBB</code> format)
     *
     * @since MIDP 2.0
     */
    public native int getDisplayColor(int color);


    // private implementation //

    /** Translated x,y coordinates */
    private int transX, transY;
    /** top/left clip bounds */
    private short clipX1, clipY1;
    /** right/bottom clip bounds */
    private int clipX2, clipY2;
    /**
     * temporary variable for top/left clip bounds
     * use a private data member instead of a new variable
     * for every invocation of clipRect
     */
    private int translatedX1, translatedY1;
    /** 
     * temporary variable for right/bottom clip bounds
     * use a private data member instead of a new variable
     * for every invocation of clipRect
     */
    private int translatedX2, translatedY2;
    /** Array to hold the clip values */
    private short clip[] = new short[4];     /* format is -- x y w h */
    /** A flag indicating the clipping state */
    private boolean clipped = false;
    /** Pixel values */
    private int rgbColor, gray, pixel;
    /** Line stroke style */
    private int style;          // line stroke style
    /** The current Font */
    private Font currentFont;
    /** The maximum width and height */
    private short maxWidth, maxHeight;
    /** The 'destination' Image to paint to */
    Image destination;

    /**
     * Retrieve the Graphics context for the given Image
     *
     * @param img The Image to get a Graphics context for
     * @return Graphics Will return a new ImageGraphics object if
     *                  the Image is non-null, otherwise will return
     *                  a new Graphics object with Display.WIDTH
     *                  maximum width and Display.HEIGHT maximum
     *                  height
     */
    static Graphics getGraphics(Image img) {
        if (img == null) {
            return new Graphics(Display.WIDTH, Display.HEIGHT);
        } else {
            return new ImageGraphics(img);
        }
    }

    /**
     * Reset this Graphics context with the given coordinates
     *
     * @param x1 The upper left x coordinate
     * @param y1 The upper left y coordinate
     * @param x2 The lower right x coordinate
     * @param y2 The lower right y coordinate
     */
    void reset(int x1, int y1, int x2, int y2) {
        transX = transY = 0;
        currentFont = Font.getDefaultFont();
        style = SOLID;
        rgbColor = gray = 0;
        pixel = getPixel(rgbColor, gray, true);

        setClip(x1, y1, x2 - x1, y2 - y1);
    }

    /**
     * Reset this Graphics context to its default dimensions
     * (same as reset(0, 0, maxWidth, maxHeight)
     */
    void reset() {
        reset(0, 0, maxWidth, maxHeight);
    }

    /**
     * Get a gray value given the RGB values
     *
     * @param red The Red pixel value
     * @param green The Green pixel value
     * @param blue The Blue pixel value
     * @return int The grayscale value corresponding to the RGB color
     */
    private static int grayVal(int red, int green, int blue) {
        /* CCIR Rec 601 luma (nonlinear rgb to nonlinear "gray") */
        return (red*76 + green*150 + blue*29) >> 8;
    }

    /**
     * Get a specific pixel value
     *
     * @param rgb
     * @param gray
     * @param isGray
     * @return int
     */
    private native int getPixel(int rgb, int gray, boolean isGray);

} // class Graphics

/**
 * <p>SYNC NOTE: Unlike the Graphics class, multiple threads may issue calls
 * on ImageGraphics instances at any time.  It is therefore the responsibility
 * of the ImageGraphics class to ensure that all public methods are MT-safe.
 * </p>
 * 
 * <p>Some methods are implicitly safe already, namely those that are native
 * methods and those that make a single atomic access to instance state.
 * Those method implementations are simply inherited from the superclass.  The
 * inherited methods are included below, within comments, to indicate this
 * fact.  If the superclass' implementation of a method changes, this class
 * may need to override it and provide locking. </p>
 * 
 * <p>Any method that has multiple accesses to shared state must be protected
 * with a synchronized block.  As for the Graphics class, all access is to the
 * state of this instance, and so locking is done on 'this' instead of on
 * Display.LCDUILock.</p>
 */
class ImageGraphics extends Graphics {

    /**
     * Constuct a new ImageGraphics
     *
     * @param img The Image to use to construct the ImageGraphics
     */
    ImageGraphics(Image img) {
        super(img.getWidth(), img.getHeight());
        destination = img;
    }

    /**
     * Translate this Graphics context by the given offset
     *
     * @param x The x coordinate offset
     * @param y The y coordinate offset
     */
    public void translate(int x, int y) {
        synchronized (this) {
            super.translate(x, y);
        }
    }

    /**
     * Set the Color of this Graphics context
     *
     * @param red The Red color component
     * @param green The Green color component
     * @param blue The Blue color component
     * @see #getColor
     */
    public void setColor(int red, int green, int blue) {
        synchronized (this) {
            super.setColor(red, green, blue);
        }
    }

    /**
     * Set the Color of this Graphics context
     *
     * @param RGB The RGB composite color value
     * @see #getColor
     */
    public void setColor(int RGB) {
        synchronized (this) {
            super.setColor(RGB);
        }
    }

    /**
     * Set the gray scale value of this Graphics context
     *
     * @param value The gray scale value
     */
    public void setGrayScale(int value) {
        synchronized (this) {
            super.setGrayScale(value);
        }
    }

    /**
     * Get the x coordinate of the clip
     *
     * @return int The x coordinate of the clip
     */
    public int getClipX() {
        synchronized (this) {
            return super.getClipX();
        }
    }

    /**
     * Get the y coordinate of the clip
     *
     * @return int The y coordinate of the clip
     */
    public int getClipY() {
        synchronized (this) {
            return super.getClipY();
        }
    }

    // SYNC NOTE: the superclass implementations of getClipWidth() and
    // getClipHeight() read a single value atomically, so no locking is 
    // necessary.  We simply inherit the implementations from the superclass.

    // public int getClipWidth();
    // public int getClipHeight();

    /**
     * Add the clip rectangle of this Graphics context
     *
     * @param x The x coordinate of the rectangle
     * @param y The y coordinate of the rectangle
     * @param w The width of the rectangle
     * @param h The height of the rectangle
     */
    public void clipRect(int x, int y, int w, int h) {
        synchronized (this) {
            super.clipRect(x, y, w, h);
        }
    }

    /**
     * Set the clip of this Graphics context
     *
     * @param x The x coordinate of the clip
     * @param y The y coordinate of the clip
     * @param w The width of the clip
     * @param h The height of the clip
     */
    public void setClip(int x, int y, int w, int h) {
        synchronized (this) {
            super.setClip(x, y, w, h);
        }
    }

    // SYNC NOTE: all of the following are native methods, which run
    // atomically, so no synchronization is necessary.  We therefore simply
    // inherit them from the superclass.

    // public native void drawLine(int x1, int y1, int x2, int y2);

    // public native void fillRect(int x, int y, int width, int height);

    // public native void drawRect(int x, int y, int width, int height);

    // public native void drawRoundRect(int x, int y, int width, int height,
    //                                  int arcWidth, int arcHeight);

    // public native void fillRoundRect(int x, int y, int width, int height,
    //                                  int arcWidth, int arcHeight);

    // public native void fillArc(int x, int y, int width, int height,
    //                            int startAngle, int arcAngle);

    // public native void drawArc(int x, int y, int width, int height,
    //                            int startAngle, int arcAngle);

    // public native void fillTriangle(int x1, int y1, int x2, int y2,
    //                                 int x3, int y3);

    // public native void drawString(java.lang.String str,
    //                               int x, int y, int anchor);

    // public native void drawSubstring(String str, int offset, int len,
    //                                  int x, int y, int anchor);

    // public native void drawChar(char character, int x, int y, int anchor);

    // public native void drawChars(char[] data, int offset, int length,
    //                              int x, int y, int anchor);

    // public native void drawImage(Image img, int x, int y, int anchor);
    
    // public native void drawRGB(int[] rgbData, int offset, int scanlength,
    //	 		          int x, int y, int width, int height,
    //		                  boolean processAlpha);

    // public native int getDisplayColor(int color);
} // class ImageGraphics