/* WCEGraphics2D.java
   Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package gnu.java.awt.peer.wce;

import gnu.java.awt.peer.wce.font.FreeTypeException;
import gnu.java.awt.peer.wce.font.FreeTypeFace;
import gnu.java.awt.peer.wce.font.FreeTypeGlyphVector;
import gnu.java.awt.peer.wce.font.WCEFontPeer;
import gnu.java.awt.peer.wce.font.WCEFontMetrics;
import gnu.java.awt.peer.wce.font.WCEGlyphVector;

import java.awt.AWTError;
import java.awt.AWTPermission;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.Paint;
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.SystemColor;
import java.awt.TexturePaint;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.FlatteningPathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;
import java.awt.image.ImagingOpException;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.awt.image.renderable.RenderContext;
import java.awt.image.renderable.RenderableImage;
import java.text.AttributedCharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Graphics2D implementation for Windows Mobile device.
 */
public class WCEGraphics2D extends Graphics2D
{
  static
  {
    initIDs ();
  }

  /**
   * Default Stroke.
   */
  private static final Stroke DEFAULT_STROKE = new BasicStroke ();

  /**
   * cache of BufferedImageWrapper
   */
  private static final Map < BufferedImage,
    BufferedImageWrapper > bufferedImageWrapperCache =
    new HashMap < BufferedImage, BufferedImageWrapper > ();

  /**
   * native graphics information.
   * this field managed by native code,
   * never try to change this field except constructor/dispose().
   */
  private int nativeGraphics;

  /**
   * target window handle. (HWND)
   */
  private final int windowHandle;

  /**
   * target Peer, or null if target peer not exists.
   */
  private final WCEComponentPeer peer;

  /**
   * 描画対象となるオフスクリーンイメージ
   * オフスクリーンイメージに描画しない場合はnull.
   */
  private final WCEOffscreenImage offscreenImage;

  /**
   * BufferedImageWrapper.
   * 
   */
  private BufferedImageWrapper bufferedImageWrapper;

  /**
   * オフセット
   */
  private final Point offset = new Point ();

  /**
   * バックグラウンドカラー
   */
  private Color bgcolor;


  /**
   * 現在のフォント
   */
  private Font font;

  /**
   * 現在のクリッピング領域
   */
  private Rectangle clip;

  /**
   * XORモードの場合の指定色
   * このフィールドがnullの場合は、setPaintMode()が指定されていると見なす
   */
  private Color xorColor;

  /**
   * setStroke(Stroke) で設定された Stroke
   */
  private Stroke stroke = DEFAULT_STROKE;

  /**
   * setPaint(Paint) で設定された情報
   */
  private Paint paint;

  /**
   * The transformation for this Graphics2D instance
   */
  private AffineTransform currentTransform = new AffineTransform ();

  /**
   * BufferedImage wrapper class
   */
  class BufferedImageWrapper
  {
    private BufferedImage targetImage;
    private int bitmapHandle;

    private int referenceCount;

    /**
     * creates BufferdImageWrapper object.
     */
    public BufferedImageWrapper (BufferedImage target)
    {
      this.targetImage = target;
      this.bitmapHandle = createDIBSectionFor (target);

      addRef ();
    }

    public int getBitmapHandle ()
    {
      return this.bitmapHandle;
    }

    public BufferedImage getBufferedImage ()
    {
      return this.targetImage;
    }

    public void addRef ()
    {
      this.referenceCount++;
    }

    public void release ()
    {
      this.referenceCount--;
      if (this.referenceCount <= 0)
	{
	  dispose ();
	}
      else
	{
	  // do nothing
	}
    }

    private void dispose ()
    {
      if (referenceCount > 0)
	{
	  throw new IllegalStateException ("referenceCount=" +
					   referenceCount);
	}
      if (this.bitmapHandle != 0)
	{
	  deleteNativeObject (this.bitmapHandle);
	  this.bitmapHandle = 0;
	}
      bufferedImageWrapperCache.remove (this.targetImage);
    }
  };

  /**
   * 指定されたpeerのスクリーンデバイスに描画する
   * インスタンスを作成する
   */
  public WCEGraphics2D (WCEComponentPeer peer)
  {
    this.windowHandle = peer.getWindowHandle ();
    this.peer = peer;
    this.offscreenImage = null;
    this.nativeGraphics = createNativeGraphicsForScreen (this.windowHandle);
    initialize ();
  }

  /**
   * 指定されたオフスクリーンイメージ描画用のインスタンスを作成する
   */
  public WCEGraphics2D (WCEOffscreenImage wceImage)
  {
    WCEComponentPeer peer = wceImage.getWCEComponentPeer ();

    this.windowHandle = peer.getWindowHandle ();
    this.peer = peer;
    this.offscreenImage = wceImage;

    int bitmapHandle = wceImage.getBitmapHandle ();
    if (bitmapHandle == 0)
      {
	throw new
	  IllegalArgumentException
	  ("wceImage.getBitmapHandle() returns invalid bitmap handle");
      }
    this.nativeGraphics =
      createNativeGraphicsForBitmap (this.windowHandle, bitmapHandle);
    initialize ();
  }

  /**
   * 指定されたBufferedImage描画用のインスタンスを作成する。
   */
  public WCEGraphics2D (BufferedImage bufferedImage)
  {
    this.windowHandle = 0;
    this.peer = null;
    this.offscreenImage = null;
    BufferedImageWrapper wrapper =
      bufferedImageWrapperCache.get (bufferedImage);
    if (wrapper == null)
      {
	wrapper = new BufferedImageWrapper (bufferedImage);
	bufferedImageWrapperCache.put (bufferedImage, wrapper);
      }
    else
      {
	wrapper.addRef ();
      }
    this.bufferedImageWrapper = wrapper;

    this.nativeGraphics =
      createNativeGraphicsForBufferedImage (wrapper.getBitmapHandle ());

    initialize ();
  }

  /**
   * ネイティブライブラリ側を初期化する
   */
  private static native void initIDs ();


  /**
   * initialize this instance.
   * member "nativeGraphics" should be initialized before call this method.
   */
  private void initialize ()
  {
    assert nativeGraphics != 0:"nativeGraphics == 0";
    Color foreground, background;
    Font font;

    if (this.peer != null)
      {
	// get default color and font from the peer.
	Component component = this.peer.getComponent ();
	foreground = component.getForeground ();
	background = component.getBackground ();
	font = component.getFont ();
      }
    else
      {
	foreground = null;
	background = null;
	font = null;
      }

    // set default values.
    if (foreground == null)
      {
	foreground = SystemColor.windowText;
      }
    setColor (foreground);

    if (bgcolor == null)
      {
	bgcolor = SystemColor.window;
      }
    setBackground (bgcolor);

    if (font == null)
      {
	// GNU Classpath 0.18までのComponent.getFont()のデフォルト値を使用する
	font = new Font ("Dialog", Font.PLAIN, 12);
      }
    setFont (font);
  }

  /**
   * 指定されたウインドウハンドルに直接描画するための nativeGraphics を生成する
   *
   * @param window
   */
  private native int createNativeGraphicsForScreen (int windowHandle);

  /**
   * 指定されたビットマップに描画するための nativeGraphics を生成する
   *
   * @param windowHandle	ウインドウハンドル
   * @param bitmapHandle	ビットマップハンドル（windowHandleと互換性のあるビットマップであることを前提にしている）
   */
  private native int createNativeGraphicsForBitmap (int windowHandle,
						    int bitmapHandle);

  /**
   * BufferedImageに描画するための nativeGraphics を生成する。
   * 描画処理が行われるたびに、ネイティブ側から対象となるBufferedImageが更新される
   *
   * @param bitmapHandle	dibSectionのビットマップハンドル。
   */
  private native int createNativeGraphicsForBufferedImage (int bitmapHandle);

  public Graphics create ()
  {
    // コピーを作成する
    WCEGraphics2D g;

    if (this.bufferedImageWrapper != null)
      {
	// BufferedImage描画用Graphics
	g = new WCEGraphics2D (this.bufferedImageWrapper.getBufferedImage ());
      }
    else if (this.offscreenImage != null)
      {
	// オフスクリーン描画用Graphics
	g = new WCEGraphics2D (this.offscreenImage);
      }
    else
      {
	// スクリーン描画用Graphics
	g = new WCEGraphics2D (this.peer);
      }

    // 原点をコピーする
    g.offset.setLocation (this.offset);
    g.translateNative (this.nativeGraphics, this.offset.x, this.offset.y);
    // g.translate(this.offset.x, this.offset.y);

    // クリッピング領域をコピーする
    if (this.clip != null)
      {
	g.setClip ((Rectangle) this.clip.clone ());
      }
    else
      {
	g.setClip (null);
      }

    g.setPaint (getPaint ());
    g.setBackground (getBackground ());
    if (this.xorColor != null)
      {
	g.setXORMode (this.xorColor);
      }
    else
      {
	g.setPaintMode ();
      }

    // カレントフォント
    g.setFont (this.font);

    return g;
  }

  public Graphics create (int x, int y, int width, int height)
  {
    WCEGraphics2D g = (WCEGraphics2D) create ();
    // 原点とクリップ領域を変更する
    g.translate (x, y);
    g.clipRect (0, 0, width, height);
    return g;
  }

  public void translate (int x, int y)
  {
    this.offset.translate (x, y);
    translateNative (this.nativeGraphics, x, y);

    // クリッピング領域も変更されたことになる。
    if (this.clip != null)
      {
	this.clip.x -= x;
	this.clip.y -= y;
	setClip (this.clip.x, this.clip.y, this.clip.width, this.clip.height);
      }
  }

    /**
     * ネイティブの原点を設定する
     */
  private native void translateNative (int nativeGraphics, int x, int y);

  /**
   * return current color.
   */
  public Color getColor ()
  {
    if (this.paint instanceof Color)
      {
	return (Color) this.paint;
      }
    else
      {
	// I've not found the document, but Sun's implementation returns Color.BLACK
	return Color.BLACK;
      }
  }

  /**
   * set current color.
   */
  public void setColor (Color c)
  {
    if (c == null)
      {
	// nullが指定された場合はBLACKを設定する
	c = Color.BLACK;
      }
    this.paint = c;
    setNativeColor (this.nativeGraphics, c.getRed (), c.getGreen (),
		    c.getBlue ());
  }


  private native void setNativeColor (int nativeGraphics, int red, int green,
				      int blue);

  public void setPaintMode ()
  {
    this.xorColor = null;
    setNativePaintMode (this.nativeGraphics);
  }

  private native void setNativePaintMode (int nativeGraphics);

  public void setXORMode (Color c1)
  {
    this.xorColor = c1;
    setNativeXORMode (this.nativeGraphics, c1.getRed (), c1.getGreen (),
		      c1.getBlue ());
  }

  private native void setNativeXORMode (int nativeGraphics, int red,
					int green, int blue);

  public Font getFont ()
  {
    return this.font;
  }

  @SuppressWarnings ("deprecation") public void setFont (Font font)
  {
    if (font != null)
      {
	this.font = font;
	WCEFontPeer peer = (WCEFontPeer) this.font.getPeer ();
	int fontHandle = peer.getFontHandle ();
	setNativeFont (this.nativeGraphics, fontHandle);
      }
  }

  private native void setNativeFont (int nativeGraphics, int fontHandle);

  @SuppressWarnings ("deprecation") public FontMetrics getFontMetrics (Font f)
  {
    WCEFontPeer peer = (WCEFontPeer) f.getPeer ();
    return peer.getFontMetrics (f);
  }

  public Rectangle getClipBounds ()
  {
    if (this.clip == null)
      {
	return null;
      }
    else
      {
	// コピーを返す
	return (Rectangle) this.clip.clone ();
      }
  }

  public void clipRect (int x, int y, int width, int height)
  {
    if (this.clip == null)
      {
	this.clip = new Rectangle (x, y, width, height);
      }
    else
      {
	// intersect current clip rect.
	this.clip =
	  this.clip.intersection (new Rectangle (x, y, width, height));
      }
    setNativeClip (this.nativeGraphics,
		   true,
		   this.clip.x + this.offset.x,
		   this.clip.y + this.offset.y,
		   this.clip.width, this.clip.height);
  }


  public void setClip (int x, int y, int width, int height)
  {
    this.clip = new Rectangle (x, y, width, height);
    setNativeClip (this.nativeGraphics,
		   true,
		   this.clip.x + this.offset.x,
		   this.clip.y + this.offset.y,
		   this.clip.width, this.clip.height);
  }

  public Shape getClip ()
  {
    if (this.clip == null)
      {
	return null;
      }
    else
      {
	return (Shape) this.clip.clone ();
      }
  }

  public void setClip (Shape clip)
  {
    if (clip == null)
      {
	this.clip = null;
	setNativeClip (this.nativeGraphics, false, 0, 0, 0, 0);

      }
    else
      {
	// 現在の実装ではRectangleのみサポートする
	this.clip = clip.getBounds ();
	setNativeClip (this.nativeGraphics,
		       true,
		       this.clip.x + this.offset.x,
		       this.clip.y + this.offset.y,
		       this.clip.width, this.clip.height);
      }
  }

  public void copyArea (int x, int y, int width, int height, int dx, int dy)
  {
    copyNativeArea (this.nativeGraphics,
		    x + this.offset.x,
		    y + this.offset.y, width, height, dx, dy);
  }

    /**
     * 指定された矩形領域をコピーする
     */
  private native void copyNativeArea (int nativeGraphics,
				      int x,
				      int y,
				      int width, int height, int dx, int dy);
    /**
     * set native clip rect.
     */
  private native void setNativeClip (int nativeGraphics,
				     boolean clipEnabled,
				     int clipx,
				     int clipy,
				     int clipwidth, int clipheight);

    /**
     * このオブジェクトの状態を、ネイティブデバイスコンテキストに反映する
     */
//      private native void setNativeParameters(int deviceContext,
//                                                                                      boolean clipEnabled,
//                                                                                      int clipX,
//                                                                                      int clipY,
//                                                                                      int clipWidth,
//                                                                                      int clipHeight,
//                                                                                      int rgb,
//                                                                                      boolean xorMode,
//                                                                                      int xorRGB,
//                                                                                      int fontHandle);

  public void drawLine (int x1, int y1, int x2, int y2)
  {
    if (isCompatibleStroke ())
      {
	drawNativeLine (this.nativeGraphics,
			x1 + offset.x,
			y1 + offset.y, x2 + offset.x, y2 + offset.y);
      }
    else
      {
	// Strokeを描画する
	fill (getStroke ().
	      createStrokedShape (new Line2D.
				  Double ((double) x1 + offset.x,
					  (double) y1 + offset.y,
					  (double) x2 + offset.x,
					  (double) y2 + offset.y)));
      }

  }

    /**
     * デバイスコンテキストを使用して線を引く
     */
  private native void drawNativeLine (int nativeGraphics,
				      int x1, int y1, int x2, int y2);


  public void drawRect (int x, int y, int width, int height)
  {
    if (isCompatibleStroke ())
      {
	drawNativeRect (this.nativeGraphics, x + offset.x, y + offset.y,
			//x,
			//y,
			width, height);
      }
    else
      {
	// Strokeを描画する
	fill (getStroke ().createStrokedShape (new Rectangle (x + offset.x,
							      y + offset.y,
							      width,
							      height)));
      }
  }

  private native void drawNativeRect (int nativeGraphics,
				      int x, int y, int width, int height);

  public void fillRect (int x, int y, int width, int height)
  {
    fillNativeRect (this.nativeGraphics,
		    x + offset.x, y + offset.y, width, height);

  }

    /**
     * デバイスコンテキストを用いて矩形を塗りつぶす
     */
  private native void fillNativeRect (int nativeGraphics,
				      int x, int y, int width, int height);

  public void clearRect (int x, int y, int width, int height)
  {
    clearNativeRect (this.nativeGraphics,
		     x + this.offset.x,
		     y + this.offset.y,
		     width, height, this.bgcolor.getRGB ());
  }

  private native void clearNativeRect (int nativeGraphics,
				       int x,
				       int y, int width, int height, int rgb);

  public void drawRoundRect (int x,
			     int y,
			     int width,
			     int height, int arcWidth, int arcHeight)
  {
    if (isCompatibleStroke ())
      {
	nativeRoundRect (this.nativeGraphics,
			 x + this.offset.x,
			 y + this.offset.y,
			 width, height, arcWidth, arcHeight, false);
      }
    else
      {
	fill (getStroke ().
	      createStrokedShape (new RoundRectangle2D.
				  Float ((float) x + offset.x,
					 (float) y + offset.y, (float) width,
					 (float) height, (float) arcWidth,
					 (float) arcHeight)));
      }
  }

  public void fillRoundRect (int x,
			     int y,
			     int width,
			     int height, int arcWidth, int arcHeight)
  {
    nativeRoundRect (this.nativeGraphics,
		     x + this.offset.x,
		     y + this.offset.y,
		     width, height, arcWidth, arcHeight, true);
  }

    /**
     * 丸コーナー付き矩形を描画する
     */
  private native void nativeRoundRect (int nativeGraphics,
				       int x,
				       int y,
				       int width,
				       int height,
				       int arcWidth,
				       int arcHeight, boolean fill);

  public void drawOval (int x, int y, int width, int height)
  {
    if (isCompatibleStroke ())
      {
	nativeOval (this.nativeGraphics,
		    x + this.offset.x,
		    y + this.offset.y, width, height, false);
      }
    else
      {
	// Strokeを描画する
	fill (getStroke ().
	      createStrokedShape (new Ellipse2D.
				  Float ((float) x + offset.x,
					 (float) y + offset.y, (float) width,
					 (float) height)));
      }

  }

  public void fillOval (int x, int y, int width, int height)
  {
    nativeOval (this.nativeGraphics,
		x + this.offset.x, y + this.offset.y, width, height, true);
  }

    /**
     * 楕円を描画する
     */
  private native void nativeOval (int deviceContext,
				  int x,
				  int y, int width, int height, boolean fill);

  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.PIE));
  }

  public void drawPolyline (int[]xPoints, int[]yPoints, int nPoints)
  {
    // オフセットの計算を行う
    int[] xp = new int[xPoints.length];
    int[] yp = new int[yPoints.length];
    for (int i = 0; i < xp.length; ++i)
      {
	xp[i] = xPoints[i] + this.offset.x;
      }
    for (int i = 0; i < yp.length; ++i)
      {
	yp[i] = yPoints[i] + this.offset.y;
      }
    drawNativePolyline (this.nativeGraphics, xp, yp, nPoints);
  }

  private native void drawNativePolyline (int nativeGraphics,
					  int[]xPoints,
					  int[]yPoints, int nPoints);

  public void drawPolygon (int[]xPoints, int[]yPoints, int nPoints)
  {
    // オフセットの計算を行う
    int[] xp = new int[xPoints.length];
    int[] yp = new int[yPoints.length];
    for (int i = 0; i < xp.length; ++i)
      {
	xp[i] = xPoints[i] + this.offset.x;
      }
    for (int i = 0; i < yp.length; ++i)
      {
	yp[i] = yPoints[i] + this.offset.y;
      }
    drawNativePolygon (this.nativeGraphics, xp, yp, nPoints);
  }

  private native void drawNativePolygon (int nativeGraphics,
					 int[]xPoints,
					 int[]yPoints, int nPoints);

  public void fillPolygon (int[]xPoints, int[]yPoints, int nPoints)
  {
    // オフセットの計算を行う
    int[] xp = new int[xPoints.length];
    int[] yp = new int[yPoints.length];
    for (int i = 0; i < xp.length; ++i)
      {
	xp[i] = xPoints[i] + this.offset.x;
      }
    for (int i = 0; i < yp.length; ++i)
      {
	yp[i] = yPoints[i] + this.offset.y;
      }
    fillNativePolygon (this.nativeGraphics, xp, yp, nPoints);
  }

  private native void fillNativePolygon (int nativeGraphics,
					 int[]xPoints,
					 int[]yPoints, int nPoints);

  private native void fillNativePolyPolygon (int nativeGraphics,
					     int[]xPoints,
					     int[]yPoints,
					     int[]polyCounts,
					     int windingRule);


  public void drawString (String str, int x, int y)
  {
    try
    {
      Font font = getFont ();
      FreeTypeFace face = null;
      if (font != null)
	{
	  WCEFontPeer peer = (WCEFontPeer) font.getPeer ();
	  face = peer.getFreeTypeFace ();
	}
      if (face != null)
	{
	  char[] text = str.toCharArray ();
	  FreeTypeGlyphVector gv = new FreeTypeGlyphVector (face,
							    font,
							    getFontRenderContext
							    (),
							    text,
							    0,
							    text.length,
							    Font.
							    LAYOUT_LEFT_TO_RIGHT);
	  drawGlyphVector (gv, x, y);
	}
      else
	{
	  drawNativeString (this.nativeGraphics, str, x + offset.x,
			    y + offset.y, xorColor != null);
	}
    }
    catch (FreeTypeException fte)
    {
      fte.printStackTrace ();
    }
  }

    /**
     * 文字列を描画する
     */
  private native void drawNativeString (int nativeGraphics, String str, int x,
					int y, boolean xorMode);

  public void drawString (AttributedCharacterIterator iterator, int x, int y)
  {
    throw new UnsupportedOperationException ("Not implemented");
  }

  public boolean drawImage (Image img, int x, int y, ImageObserver observer)
  {
    if (img == null)
      {
	// 何もせずにリターンする
	return false;
      }
    boolean result = false;
    if (img instanceof WCEVolatileImage)
      {
	img = ((WCEVolatileImage) img).getWCEOffscreenImage ();
      }
    if (img instanceof WCEImage)
      {
	// イメージの転送処理を行う
	WCEImage wceImage = (WCEImage) img;
	wceImage.addImageObserver (observer);
	int width = wceImage.getWidth ();
	int height = wceImage.getHeight ();
	int bitmapHandle = wceImage.getBitmapHandle ();
	if (bitmapHandle != 0)
	  {
	    switch (wceImage.getPreferredBltAPI ())
	      {
	      case WCEImage.BIT_BLT:
		nativeBitBlt (this.nativeGraphics,
			      x + this.offset.x,
			      y + this.offset.y,
			      width,
			      height,
			      wceImage.getWindowHandle (), bitmapHandle);
		break;

	      case WCEImage.TRANSPARENT_BLT:
		nativeTransparentBlt (this.nativeGraphics,
				      x + this.offset.x,
				      y + this.offset.y,
				      width,
				      height,
				      wceImage.getWindowHandle (),
				      bitmapHandle,
				      wceImage.getTransparentColor ());
		break;

	      case WCEImage.ALPHA_BLEND:
		// ToDo: 実装する

	      default:
		nativeBitBlt (this.nativeGraphics,
			      x + this.offset.x,
			      y + this.offset.y,
			      width,
			      height,
			      wceImage.getWindowHandle (), bitmapHandle);
		break;
	      }
	    result = true;
	  }
      }
    else if (img instanceof BufferedImage)
      {
	// 対応するDIBSectionを作る
	BufferedImage bimg = (BufferedImage) img;
	int bitmapHandle = createDIBSectionFor (bimg);
	nativeBitBlt (this.nativeGraphics, x + this.offset.x, y + this.offset.y, bimg.getWidth (), bimg.getHeight (), 0,	// ToDo: 適切なHWNDを指定する
		      bitmapHandle);
	// DIBSectionを削除する
	deleteNativeObject (bitmapHandle);
	result = true;
      }
    else
      {
	// 未サポート
	throw new AWTError ("Unsupported image type:" + img);
      }
    return result;
  }

    /**
     * ネイティブデバイスコンテキストに対してビット転送を行う。
     */
  private native void nativeBitBlt (int nativeGraphics,
				    int destX,
				    int destY,
				    int destWidth,
				    int destHeight,
				    int sourceWindowHandle,
				    int sourceBitmapHandle);
    /**
     * TransparentBlt()を呼び出す。
     */
  private native void nativeTransparentBlt (int nativeGraphics,
					    int destX,
					    int destY,
					    int destWidth,
					    int destHeight,
					    int sourceWindowHandle,
					    int sourceBitmapHandle,
					    int transparentColor);

    /**
     * ネイティブデバイスコンテキストに対してビット転送を行う。
     */
  private native void nativeStretchBlt (int nativeGraphics,
					int destX,
					int destY,
					int destWidth,
					int destHeight,
					int sourceWindowHandle,
					int sourceBitmapHandle,
					int sourceX,
					int sourceY,
					int sourceWidth, int sourceHeight);

  public boolean drawImage (Image img,
			    int x,
			    int y,
			    int width, int height, ImageObserver observer)
  {
    if (img == null)
      {
	// 何もせずにリターンする
	return false;
      }

    boolean result = false;
    if (img instanceof WCEVolatileImage)
      {
	img = ((WCEVolatileImage) img).getWCEOffscreenImage ();
      }
    if (img instanceof WCEImage)
      {
	// デバイスコンテキストを利用した転送処理を行う
	WCEImage wceImage = (WCEImage) img;
	wceImage.addImageObserver (observer);
	int sourceWidth = wceImage.getWidth ();
	int sourceHeight = wceImage.getHeight ();
	int sourceBitmapHandle = wceImage.getBitmapHandle ();
	if (sourceBitmapHandle != 0)
	  {
	    nativeStretchBlt (this.nativeGraphics,
			      x + this.offset.x,
			      y + this.offset.y,
			      width,
			      height,
			      wceImage.getWindowHandle (),
			      sourceBitmapHandle,
			      0, 0, sourceWidth, sourceHeight);
	    result = true;
	  }
      }
    else if (img instanceof BufferedImage)
      {
	// 対応するDIBSectionを作る
	BufferedImage bimg = (BufferedImage) img;
	int bitmapHandle = createDIBSectionFor (bimg);
	nativeStretchBlt (this.nativeGraphics, x + this.offset.x, y + this.offset.y, width, height, 0,	// ToDo: 適切なHWNDを指定する
			  bitmapHandle,
			  0, 0, bimg.getWidth (), bimg.getHeight ());
	// DIBSectionを削除する
	deleteNativeObject (bitmapHandle);
	result = true;
      }
    else
      {
	// 未サポート
	throw new AWTError ("Unsupported image type:" + img);
      }
    return result;
  }

  public boolean drawImage (Image img,
			    int x,
			    int y, Color bgcolor, ImageObserver observer)
  {
    // ToDo: 透明色をサポートする
    return drawImage (img, x, y, observer);
  }

  public boolean drawImage (Image img,
			    int x,
			    int y,
			    int width,
			    int height, Color bgcolor, ImageObserver observer)
  {
    // ToDo: 透明色をサポートする
    return drawImage (img, x, y, width, height, observer);
  }

  public boolean drawImage (Image img,
			    int dx1,
			    int dy1,
			    int dx2,
			    int dy2,
			    int sx1,
			    int sy1, int sx2, int sy2, ImageObserver observer)
  {
    if (img == null)
      {
	// Do nothing.
	return false;
      }

    boolean result = false;
    if (img instanceof WCEVolatileImage)
      {
	img = ((WCEVolatileImage) img).getWCEOffscreenImage ();
      }
    if (img instanceof WCEImage)
      {
	// Bit blt operation by using device context.
	WCEImage wceImage = (WCEImage) img;
	wceImage.addImageObserver (observer);
	int sourceWidth = wceImage.getWidth ();
	int sourceHeight = wceImage.getHeight ();
	int sourceBitmapHandle = wceImage.getBitmapHandle ();
	if (sourceBitmapHandle != 0)
	  {
	    // data copy.
	    nativeStretchBlt (this.nativeGraphics,
			      dx1 + this.offset.x,
			      dy1 + this.offset.y,
			      dx2 - dx1,
			      dy2 - dy1,
			      wceImage.getWindowHandle (),
			      sourceBitmapHandle,
			      sx1, sy1, sx2 - sx1, sy2 - sy1);
	    result = true;
	  }
      }
    else if (img instanceof BufferedImage)
      {
	// Creates DIBSection.
	BufferedImage bimg = (BufferedImage) img;
	int bitmapHandle = createDIBSectionFor (bimg);
	nativeStretchBlt (this.nativeGraphics,
                          dx1 + this.offset.x,
                          dy1 + this.offset.y,
			  dx2 - dx1,
			  dy2 - dy1,
                          0,	// ToDo: 適切なHWNDを指定する
			  bitmapHandle,
			  sx1, sy1, sx2 - sx1, sy2 - sy1);
	// Deletes DIBSection.
	deleteNativeObject (bitmapHandle);
	result = true;
      }
    else
      {
	// not supported.
	throw new AWTError ("Unsupported image type:" + img);
      }
    return result;
  }

  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)
  {
    // ToDo: 透明色をサポートする
    return drawImage (img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
  }

  public synchronized void dispose ()
  {
    if (this.nativeGraphics != 0)
      {
	disposeNative (this.nativeGraphics);
      }
    if (bufferedImageWrapper != null)
      {
	bufferedImageWrapper.release ();
	bufferedImageWrapper = null;
      }

    this.nativeGraphics = 0;
  }

    /**
     * デバイスコンテキストに関連付けられたオブジェクト（Region, Pen等）を削除
     * した後、デバイスコンテキストを削除する
     */
  private native void disposeNative (int nativeGraphics);


    /**
     * 指定されたShapeを描画する
     * 
     */
  public void draw (Shape s)
  {
    if (s instanceof Line2D)
      {
	Line2D line = (Line2D) s;
	drawLine ((int) line.getX1 (), (int) line.getY1 (),
		  (int) line.getX2 (), (int) line.getY2 ());

      }
    else if (s instanceof Rectangle2D)
      {
	Rectangle2D rect = (Rectangle2D) s;
	drawRect ((int) rect.getMinX (), (int) rect.getMinY (),
		  (int) rect.getWidth (), (int) rect.getHeight ());

      }
    else if (s instanceof Ellipse2D.Double)
      {
	Ellipse2D.Double ellipse = (Ellipse2D.Double) s;
	drawOval ((int) ellipse.getX (), (int) ellipse.getY (),
		  (int) ellipse.getWidth (), (int) ellipse.getHeight ());

      }
    else if (s instanceof Ellipse2D.Float)
      {
	Ellipse2D.Float ellipse = (Ellipse2D.Float) s;
	drawOval ((int) ellipse.getX (), (int) ellipse.getY (),
		  (int) ellipse.getWidth (), (int) ellipse.getHeight ());

      }
    else if (s instanceof RoundRectangle2D.Double)
      {
	RoundRectangle2D.Double round = (RoundRectangle2D.Double) s;
	drawRoundRect ((int) round.getX (), (int) round.getY (),
		       (int) round.getWidth (), (int) round.getHeight (),
		       (int) round.getArcWidth (),
		       (int) round.getArcHeight ());

      }
    else if (s instanceof RoundRectangle2D.Float)
      {
	RoundRectangle2D.Float round = (RoundRectangle2D.Float) s;
	drawRoundRect ((int) round.getX (), (int) round.getY (),
		       (int) round.getWidth (), (int) round.getHeight (),
		       (int) round.getArcWidth (),
		       (int) round.getArcHeight ());

      }
    else
      {
	if (isCompatibleStroke ())
	  {
	    // 単純なStrokeは、PathIteratorから取得した座標を点でつないで描画する
	    PathIterator pi =
	      new FlatteningPathIterator (s.getPathIterator (null), 1);
	    double[] points = new double[6];
	    double[] start = new double[2];
	    double[] current = new double[2];
	    while (!pi.isDone ())
	      {
		switch (pi.currentSegment (points))
		  {
		  case PathIterator.SEG_MOVETO:
		    start[0] = points[0];
		    start[1] = points[1];
		    current[0] = start[0];
		    current[1] = start[1];
		    break;

		  case PathIterator.SEG_LINETO:
		    drawLine ((int) current[0],
			      (int) current[1],
			      (int) points[0], (int) points[1]);
		    current[0] = points[0];
		    current[1] = points[1];
		    break;

		  case PathIterator.SEG_QUADTO:
		  case PathIterator.SEG_CUBICTO:
		    // FlatteningPathIteratorはこの値を返さないはず
		    throw new
		      IllegalStateException
		      ("Unexpected return value from currentSegument().");

		  case PathIterator.SEG_CLOSE:
		    drawLine ((int) current[0],
			      (int) current[1],
			      (int) start[0], (int) start[1]);
		    break;

		  default:
		    throw new IllegalStateException ();
		  }
		pi.next ();
	      }
	  }
	else
	  {
	    // 複雑なStrokeを描画する
	    Stroke stroke = getStroke ();
	    Shape strokedShape = stroke.createStrokedShape (s);
	    fill (strokedShape);
	  }
      }
  }

  public boolean drawImage (Image img,
			    AffineTransform xform, ImageObserver obs)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void drawImage (BufferedImage img, BufferedImageOp op, int x, int y)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void drawRenderedImage (RenderedImage img, AffineTransform xform)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void drawRenderableImage (RenderableImage img, AffineTransform xform)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void drawString (String s, float x, float y)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void drawString (AttributedCharacterIterator iterator,
			  float x, float y)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

    /**
     * Renders the text of the specified GlyphVector
     * 
     * @param g	the GlyphVector to be rendered
     * @param x the x position
     * @param y the y position
     */
  public void drawGlyphVector (GlyphVector g, float x, float y)
  {
    if (g instanceof WCEGlyphVector)
      {
	// ToDo: ちゃんと実装する
	Font font = getFont ();
	setFont (g.getFont ());
	drawString (((WCEGlyphVector) g).getText (), (int) x, (int) y);
	setFont (font);
      }
    else if (g instanceof FreeTypeGlyphVector)
      {
	FreeTypeGlyphVector ftgv = (FreeTypeGlyphVector) g;
	drawNativeFreeTypeGlyphVector (this.nativeGraphics,
				       ftgv.getNativePointer (), x + offset.x,
				       y + offset.y);
      }
    else
      {
	Shape shape = g.getOutline (x, y);
	fill (shape);
      }
  }

    /**
     * Renderes specified FreeTypeGlyphVector
     * 
     * @param nativeGraphics		the native graphics pointer.
     * @param nativeFreeTypePointer	the native FreeTypeGlyphVector object's address to be rendered
     * @param x	the x position.
     * @param y the y position
     * 
     */
  private native void drawNativeFreeTypeGlyphVector (int nativeGraphics,
						     int
						     nativeFreeTypePointer,
						     float x, float y);

    /**
     * 指定されたList<Double>の内容をfillNativePolyPolygon()に渡す。
     */
  private void fillPolyPolygon (List < Double > xPointsList,
				List < Double > yPointsList,
				List < Integer > polyCounts, int windingRule)
  {
    int size = xPointsList.size ();
    int[] xPoints = new int[size];
    int[] yPoints = new int[size];
    assert (xPoints.length == yPoints.length);
    for (int i = 0; i < size; ++i)
      {
	xPoints[i] = xPointsList.get (i).intValue () + this.offset.x;
	yPoints[i] = yPointsList.get (i).intValue () + this.offset.y;
      }
    size = polyCounts.size ();
    int[] counts = new int[size];
    for (int i = 0; i < size; ++i)
      {
	counts[i] = polyCounts.get (i);
      }

    fillNativePolyPolygon (this.nativeGraphics, xPoints, yPoints, counts,
			   windingRule);
  }

    /**
     * 指定されたShapeから座標Listを取り出す
     */
  private void extractPointsFromPathIterator (FlatteningPathIterator pi,
					      List < Double > xPointsList,
					      List < Double > yPointsList,
					      List < Integer > polygonCounts)
  {
    double[] points = new double[6];
    int prevPoints = 0;

    while (!pi.isDone ())
      {
	switch (pi.currentSegment (points))
	  {
	  case PathIterator.SEG_MOVETO:
	    // 頂点数を登録する
	    if (xPointsList.size () > 0 && prevPoints < xPointsList.size ())
	      {
		polygonCounts.add (xPointsList.size () - prevPoints);
		prevPoints = xPointsList.size ();
	      }
	    xPointsList.add (points[0]);
	    yPointsList.add (points[1]);
	    break;

	  case PathIterator.SEG_LINETO:
	    xPointsList.add (points[0]);
	    yPointsList.add (points[1]);
	    break;

	  case PathIterator.SEG_QUADTO:
	  case PathIterator.SEG_CUBICTO:
	    throw new
	      IllegalStateException
	      ("Unexpected return value from currentSegment()");

	  case PathIterator.SEG_CLOSE:
	    if (xPointsList.size () > 0)
	      {
		// 図形を閉じる
		polygonCounts.add (xPointsList.size () - prevPoints);
		prevPoints = xPointsList.size ();
	      }

	    break;

	  default:
	    throw new IllegalStateException ();
	  }
	pi.next ();
      }
  }

    /**
     * 指定されたShapeを塗りつぶす
     */
  public void fill (Shape s)
  {
    if (s instanceof Line2D)
      {
	Line2D line = (Line2D) s;
	drawLine ((int) line.getX1 (), (int) line.getY1 (),
		  (int) line.getX2 (), (int) line.getY2 ());

      }
    else if (s instanceof Rectangle2D)
      {
	// 矩形の描画
	Rectangle r = s.getBounds ();
	fillRect (r.x, r.y, r.width, r.height);

      }
    else if (s instanceof Ellipse2D.Double)
      {
	Ellipse2D.Double ellipse = (Ellipse2D.Double) s;
	fillOval ((int) ellipse.getX (), (int) ellipse.getY (),
		  (int) ellipse.getWidth (), (int) ellipse.getHeight ());

      }
    else if (s instanceof Ellipse2D.Float)
      {
	Ellipse2D.Float ellipse = (Ellipse2D.Float) s;
	fillOval ((int) ellipse.getX (), (int) ellipse.getY (),
		  (int) ellipse.getWidth (), (int) ellipse.getHeight ());


      }
    else if (s instanceof RoundRectangle2D.Double)
      {
	RoundRectangle2D.Double round = (RoundRectangle2D.Double) s;
	fillRoundRect ((int) round.getX (), (int) round.getY (),
		       (int) round.getWidth (), (int) round.getHeight (),
		       (int) round.getArcWidth (),
		       (int) round.getArcHeight ());

      }
    else if (s instanceof RoundRectangle2D.Float)
      {
	RoundRectangle2D.Float round = (RoundRectangle2D.Float) s;
	fillRoundRect ((int) round.getX (), (int) round.getY (),
		       (int) round.getWidth (), (int) round.getHeight (),
		       (int) round.getArcWidth (),
		       (int) round.getArcHeight ());

      }
    else
      {
	// PathIteratorから座標をすべて抽出する
	List < Double > xPointsList = new ArrayList < Double > ();
	List < Double > yPointsList = new ArrayList < Double > ();
	List < Integer > polyCounts = new ArrayList < Integer > ();

	FlatteningPathIterator pi =
	  new FlatteningPathIterator (s.getPathIterator (null), 1);
	extractPointsFromPathIterator (pi, xPointsList, yPointsList,
				       polyCounts);
	fillPolyPolygon (xPointsList, yPointsList, polyCounts,
			 pi.getWindingRule ());
      }
  }

  public boolean hit (Rectangle rect, Shape s, boolean onStroke)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public GraphicsConfiguration getDeviceConfiguration ()
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void setComposite (Composite comp)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

    /**
     * 現在のStrokeがGDIで描画可能であるかを返す
     */
  private boolean isCompatibleStroke ()
  {
    // Windows MobileのCreatePen()で作成できるスタイルと互換性がある場合は
    // trueを返す
    if (!(getPaint ()instanceof Color))
      {
	// 単色ではない
	return false;
      }
    if (getStroke () == DEFAULT_STROKE)
      {
	return true;
      }
    Stroke stroke = getStroke ();
    if (stroke.getClass () == BasicStroke.class)
      {
	BasicStroke bs = (BasicStroke) stroke;
	if (bs.getDashArray () != null)
	  {
	    // 破線
	    return false;
	  }
	if (bs.getLineWidth () <= 1.0f)
	  {
	    // 線の太さが1以下
	    // ToDo: AffineTransformを考慮する
	    return true;
	  }
	// CAP_SQURE, JOIN_BEVEL
	if (bs.getEndCap () == BasicStroke.CAP_SQUARE
	    && bs.getLineJoin () == BasicStroke.JOIN_BEVEL)
	  {
	    return true;
	  }
      }
    return false;
  }

  public void setPaint (Paint paint)
  {
    if (paint == null)
      {
	// nullは無視する
	return;
      }

    this.paint = paint;
    String className = paint.getClass ().getName ();

    if (paint instanceof Color)
      {
	// Colorクラス
	setColor ((Color) paint);

      }
    else if ("java.awt.GradientPaint".equals (className))
      {
	// GradientPaintクラスに関してはネイティブ側で処理を行う
	// サブクラスに対して間違った処理をしないように
	// instanceof ではなく String.equals(String) で比較している
	GradientPaint gp = (GradientPaint) paint;
	Point2D p1 = gp.getPoint1 ();
	Point2D p2 = gp.getPoint2 ();
	Color c1 = gp.getColor1 ();
	Color c2 = gp.getColor2 ();
	setNativeGradientPaint (this.nativeGraphics,
				(int) p1.getX () + this.offset.x,
				(int) p1.getY () + this.offset.y,
				c1.getRed (),
				c1.getGreen (),
				c1.getBlue (),
				(int) p2.getX () + this.offset.x,
				(int) p2.getY () + this.offset.y,
				c2.getRed (),
				c2.getGreen (),
				c2.getBlue (), gp.isCyclic ());
      }
    else if ("java.awt.TexturePaint".equals (className))
      {
	// TexturePaintクラスに関してはネイティブ側で処理を行う
	// サブクラスに対して間違った処理をしないように
	// instanceof ではなく String.equals(String) で比較している
	TexturePaint tp = (TexturePaint) paint;
	BufferedImage image = tp.getImage ();
	Rectangle anchor = tp.getAnchorRect ().getBounds ();

	// DIBSectionを作成する
	int bitmapHandle = createDIBSectionFor (image);

	// TexturePaintを設定する
	setNativeTexturePaint (this.nativeGraphics,
			       bitmapHandle,
			       anchor.x,
			       anchor.y, anchor.width, anchor.height);
      }
    else
      {

	// その他のクラス
	throw new UnsupportedOperationException ("Unsupported paint type:" +
						 paint);
      }
  }

  /**
   * 指定されたBufferedImageの内容とデータ転送を行うことを目的とした
   * DIBSectionを作成し、そのハンドルを返す。
   * 転送を高速に行うことができるように、できるだけ同じフォーマットを持つDIBSection
   * を作成する。
     */
  private int createDIBSectionFor (BufferedImage image)
  {
    ColorModel cm = image.getColorModel ();
    SampleModel sm = image.getSampleModel ();
    DataBuffer db = image.getRaster ().getDataBuffer ();
    final int width = image.getWidth ();
    final int height = image.getHeight ();
    int type = image.getType ();
    int bitCount = 0;
    int result = 0;

    switch (type)
      {
      case BufferedImage.TYPE_INT_RGB:
      case BufferedImage.TYPE_INT_ARGB:
	{
	  if (db instanceof DataBufferInt)
	    {
	      // 32ビットのDIBSectionを作成する
	      bitCount = 32;
	    }
	}
	break;

      case BufferedImage.TYPE_USHORT_565_RGB:
      case BufferedImage.TYPE_USHORT_555_RGB:
	{
	  if (db instanceof DataBufferUShort)
	    {
	      // 16ビットのDIBSectionを作成する
	      bitCount = 16;
	    }
	}
	break;
      }

    if (bitCount == 0)
      {
	// 32ビットのDIBSectionを作成する
	bitCount = 32;
	type = BufferedImage.TYPE_INT_RGB;
      }
    result = createNativeDIBSection (width, height, bitCount, type);

    // BufferedImageの内容でDIBSectionを初期化する
    if (result != 0)
      {
	copyImage (image, result);
      }
    return result;
  }

  /**
   * ネイティブDIBSectionを作成し、そのビットマップハンドルを返す
   */
  private native int createNativeDIBSection (int width, int height,
					     int bitCount, int type);

    /**
     * ネイティブAPI DeleteObject(int)を呼び出す。
     */
  private native void deleteNativeObject (int gdiObjectHandle);

    /**
     * 指定されたBufferedImageの内容を返すピクセルに
     * 直接アクセス可能なプリミティブ配列を返す
     * 直接アクセスできない場合は null を返す。
     */
  private Object getPixelsOf (BufferedImage image)
  {
    DataBuffer db = image.getRaster ().getDataBuffer ();
    Object result = null;
    switch (image.getType ())
      {
      case BufferedImage.TYPE_INT_RGB:
      case BufferedImage.TYPE_INT_ARGB:
	if (db instanceof DataBufferInt)
	  {
	    result = ((DataBufferInt) db).getData ();
	  }
	break;

      case BufferedImage.TYPE_USHORT_565_RGB:
      case BufferedImage.TYPE_USHORT_555_RGB:
	if (db instanceof DataBufferUShort)
	  {
	    result = ((DataBufferUShort) db).getData ();
	  }
	break;
      }
    return result;
  }

    /**
     * return pixel data of BufferedImage if this WCEGraphics2D instance created for BufferedImage.
     */
  protected Object getPixelsOfBufferedImage ()
  {
    if (this.bufferedImageWrapper != null)
      {
	return getPixelsOf (this.bufferedImageWrapper.getBufferedImage ());
      }
    return null;
  }

    /**
     * 指定されたBufferedImageの内容をDIBSectionに設定する
     */
  private void copyImage (BufferedImage image, int bitmapHandle)
  {
    Object pixels = getPixelsOf (image);
    if (pixels == null)
      {
	// コピーされたデータを得る
	pixels =
	  image.getRGB (0, 0, image.getWidth (), image.getHeight (), null, 0,
			image.getWidth ());
      }

    if (pixels instanceof int[])
      {
	writeNativeDIBSectionInt (bitmapHandle, (int[]) pixels,
				  image.getType ());
      }
    else if (pixels instanceof short[])
      {
	writeNativeDIBSectionUShort (bitmapHandle, (short[]) pixels,
				     image.getType ());
      }
    else
      {
	// エラー
	throw new AWTError ("Invalid pixel type:" +
			    pixels.getClass ().getName ());
      }
  }

    /**
     * 描画対象であるBufferedImageの内容を、DIBSectionの内容を用いて更新する。
     * このメソッドは、ネイティブ実装側で直接BufferedImage内のデータにアクセスできなかった場合のみ
     * ネイティブ実装側から呼び出される。
     */
  void updateBufferedImage ()
  {
    final int bitmapHandle = this.bufferedImageWrapper.getBitmapHandle ();
    final BufferedImage image = this.bufferedImageWrapper.getBufferedImage ();
    final int[] pixels =
      image.getRGB (0, 0, image.getWidth (), image.getHeight (), null, 0,
		    image.getWidth ());
    readNativeDIBSectionInt (bitmapHandle, pixels, image.getType ());
    image.setRGB (0, 0, image.getWidth (), image.getHeight (), pixels, 0,
		  image.getWidth ());
  }

    /**
     * write specified pixels to the DIBSection.
     *
     */
  private native void writeNativeDIBSectionInt (int bitmapHandle, int[]pixels,
						int type);

    /**
     * write specified pixels to the DIBSection.
     *
     */
  private native void writeNativeDIBSectionUShort (int bitmapHandle,
						   short[]pixels, int type);

    /**
     * read all pixel data from the DIBSection.
     *
     */
  private native void readNativeDIBSectionInt (int bitmapHandle, int[]pixels,
					       int type);

    /**
     * read all pixel data from the DIBSection.
     *
     */
  private native void readNativeDIBSectionUShort (int bitmapHandle,
						  short[]pixels, int type);

    /**
     * GradientPaintを設定する
     */
  private native void setNativeGradientPaint (int nativeGraphics,
					      int x1,
					      int y1,
					      int red1,
					      int green1,
					      int blue1,
					      int x2,
					      int y2,
					      int re2,
					      int green2,
					      int blue2, boolean cyclic);

    /**
     * TexturePaintを設定する
     */
  private native void setNativeTexturePaint (int nativeGraphics,
					     int bitmapHandle,
					     int anchorX,
					     int anchorY,
					     int anchorWidth,
					     int anchorHeight);


  public void setStroke (Stroke s)
  {
    if (s == null)
      {
	return;
      }
    if (s.getClass () == BasicStroke.class)
      {
	BasicStroke bs = (BasicStroke) s;
	setNativePenWidth (this.nativeGraphics, (int) bs.getLineWidth ());
      }
    this.stroke = s;
  }

    /**
     * CreatePen()で作成するGDIペンオブジェクトの太さを定義する
     * ペンは、drawNativeLine(), drawNativeRect(), nativeOval(), nativeRoundRect() で使用される
     */
  private native void setNativePenWidth (int nativeGraphics, int width);

  public void setRenderingHint (RenderingHints.Key hintKey, Object hintValue)
  {
    // ToDo: 実装する
    // 現在の実装では無視
  }

  public Object getRenderingHint (RenderingHints.Key hintKey)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void setRenderingHints (Map hints)
  {
    // ToDo: 実装する
    // 現在の実装では無視
  }

  public void addRenderingHints (Map hints)
  {
    // ToDo: 実装する
    // 現在の実装では無視
  }

  public RenderingHints getRenderingHints ()
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void translate (double tx, double ty)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void rotate (double theta)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void rotate (double theta, double x, double y)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void scale (double sx, double sy)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void shear (double shx, double shy)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void transform (AffineTransform Tx)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void setTransform (AffineTransform Tx)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public AffineTransform getTransform ()
  {
    if (this.currentTransform != null)
      {
	return (AffineTransform) this.currentTransform.clone ();
      }
    else
      {
	return new AffineTransform ();
      }
  }

  public Paint getPaint ()
  {
    return this.paint;
  }

  public Composite getComposite ()
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public void setBackground (Color color)
  {
    this.bgcolor = color;
  }

  public Color getBackground ()
  {
    return this.bgcolor;
  }

  public Stroke getStroke ()
  {
    return this.stroke;
  }

  public void clip (Shape s)
  {
    // ToDo: 実装する
    throw new UnsupportedOperationException ("Not implemented");
  }

  public FontRenderContext getFontRenderContext ()
  {
    return new FontRenderContext (this.currentTransform, false, true);
  }
}
