chunquedong avatar chunquedong committed 6c1e8a8 Draft

fgfxFwt Graphics test

Comments (0)

Files changed (26)

       `../common/build.fan`,
       `fgfx2d/build.fan`,
       `wtk/build.fan`,
+      `fgfxFwt/build.fan`,
       `widget/build.fan`
     ]
   }

gui/fgfxFwt/java/fan/fgfxFwt/FwtToolkitEnvPeer.java

+//
+// Copyright (c) 2011, chunquedong
+// Licensed under the Academic Free License version 3.0
+//
+// History:
+//   2011-7-4  Jed Young  Creation
+//
+
+package fan.fgfxFwt;
+
+import fan.concurrent.Actor;
+import fan.fgfx2d.Graphics;
+import fan.sys.*;
+
+public class FwtToolkitEnvPeer
+{
+  public static FwtToolkitEnvPeer make(FwtToolkitEnv self)
+  {
+    FwtToolkitEnvPeer peer = new FwtToolkitEnvPeer();
+    return peer;
+  }
+
+  public static void initGfxEnv()
+  {
+    Actor.locals().set("fgfx2d.env", SwtGfxEnv.instance);
+  }
+
+  public static Graphics toGraphics(fan.gfx.Graphics fg)
+  {
+    fan.fwt.FwtGraphics fwt = (fan.fwt.FwtGraphics)fg;
+    return new SwtGraphics(fwt.gc());
+  }
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtConstImage.java

+package fan.fgfxFwt;
+
+
+import org.eclipse.swt.graphics.Rectangle;
+
+import fan.fgfx2d.ConstImage;
+import fan.fgfx2d.Size;
+
+public class SwtConstImage implements ConstImage{
+
+  private org.eclipse.swt.graphics.Image image;
+
+  public org.eclipse.swt.graphics.Image getImage(){ return image; };
+
+  SwtConstImage(org.eclipse.swt.graphics.Image image) {
+    this.image = image;
+  }
+
+  @Override
+  public Size size() {
+    Rectangle r = image.getBounds();
+    return Size.make(r.width, r.height);
+  }
+
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtFont.java

+package fan.fgfxFwt;
+
+import fan.sys.Func;
+
+import org.eclipse.swt.graphics.GC;
+
+import fan.fgfx2d.*;
+
+public class SwtFont extends Font {
+
+  private org.eclipse.swt.graphics.Font nfont = null;
+  private org.eclipse.swt.graphics.FontMetrics fontMetrics = null;
+
+  public static Font makeAwtFont(Func func)
+  {
+    Font f = new SwtFont();
+    func.enterCtor(f);
+    func.call(f);
+    func.exitCtor();
+    return f;
+  }
+
+  public org.eclipse.swt.graphics.Font getNFont() {
+    if (nfont == null) {
+      nfont = SwtUtil.toFont(this);
+    }
+    return nfont;
+  }
+
+  private GC scratchGC()
+  {
+    GC gc = SwtUtil.scratchG();
+    gc.setFont(nfont);
+    return gc;
+  }
+
+  public org.eclipse.swt.graphics.FontMetrics getFontMetrics() {
+    if (fontMetrics == null) {
+      fontMetrics = scratchGC().getFontMetrics();
+    }
+    return fontMetrics;
+  }
+
+
+  @Override
+  public long ascent() {
+    return getFontMetrics().getAscent();
+  }
+
+  @Override
+  public long descent() {
+    return getFontMetrics().getDescent();
+  }
+
+  @Override
+  public void dispose() {
+  }
+
+  @Override
+  public long height() {
+    return getFontMetrics().getHeight();
+  }
+
+  @Override
+  public long leading() {
+    return getFontMetrics().getLeading();
+  }
+
+  @Override
+  public long width(String s) {
+    return scratchGC().textExtent(s).x;
+  }
+
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtGfxEnv.java

+//
+// Copyright (c) 2011, chunquedong
+// Licensed under the Academic Free License version 3.0
+//
+// History:
+//   2011-09-09  Jed Young  Creation
+//
+package fan.fgfxFwt;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import fan.fgfx2d.*;
+import fan.sys.Func;
+import fan.sys.IOErr;
+import fan.sys.InStream;
+import fan.sys.SysInStream;
+import fan.sys.Uri;
+
+public class SwtGfxEnv extends GfxEnv {
+
+  static final SwtGfxEnv instance = new SwtGfxEnv();
+  private SwtGfxEnv() {}
+
+  @Override
+  public boolean contains(Path path, double x, double y) {
+    org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
+    return p.contains((float)x, (float)y, SwtUtil.scratchG(), false);
+  }
+
+  @Override
+  public Image fromUri(Uri uri, Func onLoad) {
+    if (uri.scheme().equals("http")) {
+      onLoad = (Func) onLoad.toImmutable();
+      SwtImage p = new SwtImage();
+      loadFromWeb(p, uri, onLoad);
+      return p;
+    }
+
+    InputStream jin = SysInStream.java(((fan.sys.File) uri.get()).in());
+    SwtImage p = new SwtImage();
+    streamToImage(jin, p);
+    onLoad.call(p);
+    return p;
+  }
+
+  public Image fromStream(InStream in)
+  {
+    InputStream jin = SysInStream.java(in);
+    SwtImage p = new SwtImage();
+    streamToImage(jin, p);
+    return p;
+  }
+
+  private static void loadFromWeb(final SwtImage p, final Uri uri,
+      final Func onLoad) {
+    new Thread(new Runnable() {
+      public void run() {
+        InputStream jin;
+        try {
+          URL requestUrl = new URL(uri.toStr());
+          URLConnection con = requestUrl.openConnection();
+          jin = con.getInputStream();
+        } catch (IOException e) {
+          throw IOErr.make(e);
+        }
+
+        streamToImage(jin, p);
+        onLoad.call(p);
+      }
+    }).start();
+  }
+
+  private static void streamToImage(InputStream jin, SwtImage p) {
+    org.eclipse.swt.graphics.Image image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), jin);
+    p.setImage(image);
+  }
+
+  @Override
+  public Image makeImage(Size size) {
+    org.eclipse.swt.graphics.Image image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), (int)size.w, (int)size.h);
+    SwtImage p = new SwtImage();
+    p.setImage(image);
+    return p;
+  }
+
+  @Override
+  public ConstImage makeConstImage(Uri uri) {
+    InputStream jin;
+
+    if (uri.scheme().equals("http")) {
+      try {
+        URL requestUrl = new URL(uri.toStr());
+        URLConnection con = requestUrl.openConnection();
+        jin = con.getInputStream();
+      } catch (IOException e) {
+        throw IOErr.make(e);
+      }
+    } else {
+      jin = SysInStream.java(((fan.sys.File) uri.get()).in());
+    }
+
+    org.eclipse.swt.graphics.Image image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), jin);
+    try{
+      jin.close();
+     } catch (IOException e) {}
+    return new SwtConstImage(image);
+  }
+
+  @Override
+  public Font makeFont(Func func) {
+    return SwtFont.makeAwtFont(func);
+  }
+
+  @Override
+  public PointArray makePointArray(long size) {
+    PointArray pa = new SwtPointArray((int)size);
+    return pa;
+  }
+
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtGraphics.java

+//
+// Copyright (c) 2011, chunquedong
+// Licensed under the Academic Free License version 3.0
+//
+// History:
+//   2011-09-09  Jed Young  Creation
+//
+package fan.fgfxFwt;
+
+import java.util.Stack;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Pattern;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Region;
+import org.eclipse.swt.graphics.Transform;
+import org.eclipse.swt.events.PaintEvent;
+
+import fan.fgfxMath.Transform2D;
+import fan.fgfx2d.*;
+import fan.sys.ArgErr;
+import fan.sys.FanObj;
+
+public class SwtGraphics implements Graphics {
+
+  GC gc;
+  Pen pen = Pen.defVal;
+  Brush brush = Color.black;
+  Font font;
+  int alpha = 255;
+  Stack<State> stack = new Stack<State>();
+
+  public SwtGraphics(PaintEvent e)
+  {
+    this(e.gc, e.x, e.y, e.width, e.height);
+  }
+
+  public SwtGraphics(GC gc)
+  {
+    this.gc = gc;
+  }
+
+  public SwtGraphics(GC gc, int x, int y, int w, int h)
+  {
+    this.gc = gc;
+    clip(Rect.make(x, y, w, h));
+  }
+
+  public Brush brush()
+  {
+    return brush;
+  }
+
+  public void brush(Brush brush)
+  {
+    this.brush = brush;
+    Pattern oldfg = gc.getForegroundPattern();
+    Pattern oldbg = gc.getBackgroundPattern();
+    try
+    {
+      if (brush instanceof Color)
+      {
+        int ca = (int)((Color)brush).a();
+        gc.setAlpha((alpha == 255) ? ca : (int)((alpha * ca) / 255));
+
+        org.eclipse.swt.graphics.Color c  = SwtUtil.toSwtColor((Color)brush);
+        gc.setForeground(c);
+        gc.setBackground(c);
+        gc.setForegroundPattern(null);
+        gc.setBackgroundPattern(null);
+      }
+      else if (brush instanceof Gradient)
+      {
+        // can't really map SWT model to CSS model well
+        Pattern p = pattern((Gradient)brush, 0, 0, 100, 100);
+        gc.setForegroundPattern(p);
+        gc.setBackgroundPattern(p);
+      }
+      else if (brush instanceof fan.gfx.Pattern)
+      {
+        Pattern p = pattern((fan.fgfx2d.Pattern)brush);
+        gc.setForegroundPattern(p);
+        gc.setBackgroundPattern(p);
+      }
+      else
+      {
+        throw ArgErr.make("Unsupported brush type: " + FanObj.typeof(brush));
+      }
+    }
+    finally
+    {
+      if (oldfg != null) oldfg.dispose();
+      if (oldbg != null) oldbg.dispose();
+    }
+  }
+
+  private Pattern pattern(Gradient g, float vx, float vy, float vw, float vh)
+  {
+    // only support two gradient stops
+    GradientStop s1 = (GradientStop)g.stops.get(0);
+    GradientStop s2 = (GradientStop)g.stops.get(-1L);
+    boolean x1Percent = g.x1Unit == Gradient.percent;
+    boolean y1Percent = g.y1Unit == Gradient.percent;
+    boolean x2Percent = g.x2Unit == Gradient.percent;
+    boolean y2Percent = g.y2Unit == Gradient.percent;
+
+    // start
+    float x1 = vx + g.x1;
+    float y1 = vy + g.y1;
+    float x2 = vx + g.x2;
+    float y2 = vy + g.y2;
+
+    // handle percentages
+    if (x1Percent) x1 = vx + vw * g.x1/100f;
+    if (y1Percent) y1 = vy + vh * g.y1/100f;
+    if (x2Percent) x2 = vx + vw * g.x2/100f;
+    if (y2Percent) y2 = vy + vh * g.y2/100f;
+
+    // System.out.println(g + "[" + vx + "," + vy + "," + vw + "," + vh + "]");
+    // System.out.println("  => " + x1 + "," + y1 + "  " + x2 + "," + y2);
+
+    // alpha
+    int a1 = (int)s1.color.a();
+    int a2 = (int)s2.color.a();
+    if (alpha != 255)
+    {
+      a1 = (int)((alpha * a1) / 255);
+      a2 = (int)((alpha * a2) / 255);
+    }
+
+    return new Pattern(SwtUtil.getDisplay(),
+        x1, y1, x2, y2,
+        SwtUtil.toSwtColor(s1.color), a1,
+        SwtUtil.toSwtColor(s2.color), a2);
+  }
+
+  private Pattern pattern(fan.fgfx2d.Pattern p)
+  {
+    return new Pattern(SwtUtil.getDisplay(), SwtUtil.toSwtImage(p.image));
+  }
+
+  public Pen pen()
+  {
+    return pen;
+  }
+
+  public void pen(Pen pen)
+  {
+    this.pen = pen;
+    gc.setLineWidth((int)pen.width);
+    gc.setLineCap(penCap(pen.cap));
+    gc.setLineJoin(penJoin(pen.join));
+    gc.setLineDash(pen.dash != null ? pen.dash.toInts() : null);
+  }
+
+  private static int penCap(long cap)
+  {
+    if (cap == Pen.capSquare) return SWT.CAP_SQUARE;
+    if (cap == Pen.capButt)   return SWT.CAP_FLAT;
+    if (cap == Pen.capRound)  return SWT.CAP_ROUND;
+    throw new IllegalStateException("Invalid pen.cap " + cap);
+  }
+
+  private static int penJoin(long join)
+  {
+    if (join == Pen.joinMiter) return SWT.JOIN_MITER;
+    if (join == Pen.joinBevel) return SWT.JOIN_BEVEL;
+    if (join == Pen.joinRound) return SWT.JOIN_ROUND;
+    throw new IllegalStateException("Invalid pen.join " + join);
+  }
+
+  public Font font()
+  {
+    return font;
+  }
+
+  public void font(Font font)
+  {
+    this.font = font;
+    this.gc.setFont(((SwtFont)font).getNFont());
+  }
+
+  public boolean antialias()
+  {
+    return gc.getAntialias() == SWT.ON;
+  }
+
+  public void antialias(boolean on)
+  {
+    int val = on ? SWT.ON : SWT.OFF;
+    gc.setAntialias(val);
+    gc.setTextAntialias(val);
+  }
+
+  public long alpha()
+  {
+    return alpha;
+  }
+
+  public void alpha(long alpha)
+  {
+    this.alpha = (int)alpha;
+    brush(this.brush);
+  }
+
+  public Graphics drawLine(long x1, long y1, long x2, long y2)
+  {
+    gc.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
+    return this;
+  }
+
+  public Graphics drawRect(long x, long y, long w, long h)
+  {
+    gc.drawRectangle((int)x, (int)y, (int)w, (int)h);
+    return this;
+  }
+
+  public Graphics fillRect(long x, long y, long w, long h)
+  {
+    // this is one case where we optimize gradients for view rect
+    if (brush instanceof Gradient)
+    {
+      Pattern newbg = pattern((Gradient)brush, x, y, w, h);
+      Pattern oldbg = gc.getBackgroundPattern();
+      gc.setBackgroundPattern(newbg);
+      gc.fillRectangle((int)x, (int)y, (int)w, (int)h);
+      gc.setBackgroundPattern(oldbg);
+      newbg.dispose();
+    }
+    else
+    {
+      gc.fillRectangle((int)x, (int)y, (int)w, (int)h);
+    }
+    return this;
+  }
+
+  public Graphics drawRoundRect(long x, long y, long w, long h, long wArc, long hArc)
+  {
+    gc.drawRoundRectangle((int)x, (int)y, (int)w, (int)h, (int)wArc, (int)hArc);
+    return this;
+  }
+
+  public Graphics fillRoundRect(long x, long y, long w, long h, long wArc, long hArc)
+  {
+    // this is one case where we optimize gradients for view rect
+    if (brush instanceof Gradient)
+    {
+      Pattern newbg = pattern((Gradient)brush, x, y, w, h);
+      Pattern oldbg = gc.getBackgroundPattern();
+      gc.setBackgroundPattern(newbg);
+      gc.fillRoundRectangle((int)x, (int)y, (int)w, (int)h, (int)wArc, (int)hArc);
+      gc.setBackgroundPattern(oldbg);
+      newbg.dispose();
+    }
+    else
+    {
+      gc.fillRoundRectangle((int)x, (int)y, (int)w, (int)h, (int)wArc, (int)hArc);
+    }
+    return this;
+  }
+
+  public Graphics drawOval(long x, long y, long w, long h)
+  {
+    gc.drawOval((int)x, (int)y, (int)w, (int)h);
+    return this;
+  }
+
+  public Graphics fillOval(long x, long y, long w, long h)
+  {
+    gc.fillOval((int)x, (int)y, (int)w, (int)h);
+    return this;
+  }
+
+  public Graphics drawArc(long x, long y, long w, long h, long s, long a)
+  {
+    gc.drawArc((int)x, (int)y, (int)w, (int)h, (int)s, (int)a);
+    return this;
+  }
+
+  public Graphics fillArc(long x, long y, long w, long h, long s, long a)
+  {
+    gc.fillArc((int)x, (int)y, (int)w, (int)h, (int)s, (int)a);
+    return this;
+  }
+
+  public Graphics drawText(String text, long x, long y)
+  {
+    int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT;
+    gc.drawText(text, (int)x, (int)y, flags);
+    return this;
+  }
+
+  public Graphics drawImage(Image img, long x, long y)
+  {
+    gc.drawImage(SwtUtil.toSwtImage(img), (int)x, (int)y);
+    return this;
+  }
+
+  public Graphics copyImage(Image img, Rect s, Rect d)
+  {
+    gc.drawImage(SwtUtil.toSwtImage(img),
+      (int)s.x, (int)s.y, (int)s.w, (int)s.h,
+      (int)d.x, (int)d.y, (int)d.w, (int)d.h);
+    return this;
+  }
+
+  public Graphics clip(Rect r)
+  {
+    Rectangle a = gc.getClipping();
+    Rectangle b = new Rectangle((int)r.x, (int)r.y, (int)r.w, (int)r.h);
+    gc.setClipping(a.intersection(b));
+    return this;
+  }
+
+  public Rect clipBounds()
+  {
+    Rectangle a = gc.getClipping();
+    return Rect.make(a.x, a.y, a.width, a.height);
+  }
+
+  public void dispose()
+  {
+    gc.dispose();
+  }
+
+//////////////////////////////////////////////////////////////////////////
+// State
+//////////////////////////////////////////////////////////////////////////
+
+  public void push()
+  {
+    State s = new State();
+    s.pen   = pen;
+    s.brush = brush;
+    s.font  = font;
+    s.antialias = gc.getAntialias();
+    s.textAntialias = gc.getTextAntialias();
+    s.alpha = alpha;
+    s.transform = new Transform(gc.getDevice());
+    gc.getTransform(s.transform);
+    s.clip = gc.getClipping();
+    stack.push(s);
+  }
+
+  public void pop()
+  {
+    State s = (State)stack.pop();
+    alpha = s.alpha;
+    pen(s.pen);
+    brush(s.brush);
+    font(s.font);
+    gc.setAntialias(s.antialias);
+    gc.setTextAntialias(s.textAntialias);
+    gc.setTransform(s.transform);
+    s.transform.dispose();
+    gc.setClipping(s.clip);
+  }
+
+  static class State
+  {
+    Pen pen;
+    Brush brush;
+    Font font;
+    int antialias;
+    int textAntialias;
+    int alpha;
+    Transform transform;
+    Rectangle clip;
+  }
+
+  public SwtGraphics drawPath(Path path)
+  {
+    org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
+    gc.drawPath(p);
+    p.dispose();
+    return this;
+  }
+  public SwtGraphics fillPath(Path path)
+  {
+    org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
+    gc.fillPath(p);
+    p.dispose();
+    return this;
+  }
+
+  public SwtGraphics drawPolyline(PointArray list)
+  {
+    SwtPointArray pa = (SwtPointArray)list;
+    gc.drawPolyline(pa.array);
+    return this;
+  }
+  public SwtGraphics fillPolygon(PointArray list)
+  {
+    SwtPointArray pa = (SwtPointArray)list;
+    gc.fillPolygon(pa.array);
+    return this;
+  }
+
+  @Override
+  public Graphics drawPolygon(PointArray list) {
+    SwtPointArray pa = (SwtPointArray)list;
+    gc.drawPolygon(pa.array);
+    return this;
+  }
+
+  @Override
+  public void transform(Transform2D trans) {
+    Transform t = SwtUtil.toSwtTransform(trans);
+    gc.setTransform(t);
+    t.dispose();
+  }
+
+  @Override
+  public Transform2D transform() {
+    Transform t = new Transform(SwtUtil.getDisplay());
+    gc.getTransform(t);
+    Transform2D trans = SwtUtil.toTransform(t);
+    t.dispose();
+    return trans;
+  }
+
+  public SwtGraphics clipPath(Path path)
+  {
+    if (!gc.isClipped())
+    {
+      org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
+      gc.setClipping(p);
+      p.dispose();
+      return this;
+    }
+
+    Region region  = new Region();
+    gc.getClipping(region);
+
+    gc.setClipping(SwtUtil.toSwtPath(path));
+    Region region2  = new Region();
+    gc.getClipping(region2);
+
+    region.intersect(region2);
+    gc.setClipping(region);
+    return this;
+  }
+
+  /**
+   * auto free resource
+   */
+  @Override
+  protected void finalize()
+  {
+    if (!gc.isDisposed()) gc.dispose();
+  }
+
+  @Override
+  public Composite composite() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void composite(Composite arg0) {
+    // TODO Auto-generated method stub
+
+  }
+
+  public GC gc() { return this.gc; }
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtImage.java

+//
+// Copyright (c) 2011, chunquedong
+// Licensed under the Academic Free License version 3.0
+//
+// History:
+//   2011-08-18  Jed Young  Creation
+//
+
+package fan.fgfxFwt;
+
+import java.io.OutputStream;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+
+import fan.fgfx2d.*;
+import fan.sys.MimeType;
+import fan.sys.OutStream;
+import fan.sys.UnsupportedErr;
+import fanx.interop.Interop;
+
+public class SwtImage implements BufImage {
+  private boolean imageChanged = false;
+  private boolean painted = false;
+  private boolean isLoaded = false;
+
+  private org.eclipse.swt.graphics.Image image;
+  private org.eclipse.swt.graphics.ImageData imageData;
+
+  public void setImage(org.eclipse.swt.graphics.Image m)
+  {
+    image = m;
+    imageData = m.getImageData();
+    isLoaded = true;
+  }
+
+  public org.eclipse.swt.graphics.Image getImage()
+  {
+    if (!imageChanged) return image;
+    if (!isLoaded) return null;
+
+    //create new image
+    image.dispose();
+    image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), imageData);
+    imageChanged = false;
+    return image;
+  }
+
+  public ImageData getImageData()
+  {
+    if (painted)
+    {
+      imageData = image.getImageData();
+      painted = false;
+    }
+    return imageData;
+  }
+
+  public Size size() {
+    return Size.make(imageData.width, imageData.height);
+  }
+
+  public long getPixel(long x, long y) {
+    ImageData data = getImageData();
+    return data.getPixel((int) x, (int) y);
+  }
+
+  public void setPixel(long x, long y, long value) {
+    ImageData data = getImageData();
+    data.setPixel((int)x, (int)y, (int)value);
+    imageChanged = true;
+  }
+
+  /**
+   * save image to outSteam
+   */
+  public void save(OutStream out, MimeType format)
+  {
+    ImageLoader loader = new ImageLoader();
+    loader.data = new ImageData[] { getImageData() };
+    OutputStream jout = Interop.toJava(out);
+
+    int swtFormat = SWT.IMAGE_PNG;
+    String subType = format.subType();
+    if (subType.equals("png")) swtFormat = SWT.IMAGE_PNG;
+    else if (subType.equals("gif")) swtFormat = SWT.IMAGE_GIF;
+    else if (subType.equals("jpeg")) swtFormat = SWT.IMAGE_JPEG;
+    else if (subType.equals("jpg")) swtFormat = SWT.IMAGE_JPEG;
+    else if (subType.equals("bmp")) swtFormat = SWT.IMAGE_BMP;
+    else if (subType.equals("tiff")) swtFormat = SWT.IMAGE_TIFF;
+    else if (subType.equals("ico")) swtFormat = SWT.IMAGE_ICO;
+    else throw UnsupportedErr.make("unsupported image type: "+subType);
+
+    loader.save(jout, swtFormat);
+  }
+
+  public void save(OutStream out) {
+    save(out, MimeType.forExt("png"));
+  }
+
+  public boolean isLoaded() {
+    return image != null;
+  }
+
+  /**
+   * get graphics context from image
+   */
+  public Graphics graphics() {
+    int w = (int)size().w;
+    int h = (int)size().h;
+    painted = true;
+    return new SwtGraphics(new GC(getImage()), 0, 0, w, h);
+  }
+
+  @Override
+  public void dispose() {
+    if (!image.isDisposed()) image.dispose();
+  }
+
+  /**
+   * auto free resource
+   */
+  @Override
+  protected void finalize()
+  {
+    dispose();
+  }
+
+  @Override
+  public ConstImage toConst() {
+    throw UnsupportedErr.make();
+  }
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtPointArray.java

+package fan.fgfxFwt;
+
+import fan.fgfx2d.*;
+
+public class SwtPointArray implements PointArray {
+
+  public int[] array;
+
+  SwtPointArray(int size) {
+    array = new int[size+size];
+  }
+
+  @Override
+  public long getX(long i) {
+    return array[(int)i*2];
+  }
+
+  @Override
+  public void setX(long i, long v) {
+    array[(int)i*2] = (int)v;
+  }
+
+  @Override
+  public long getY(long i) {
+    return array[(int)i*2+1];
+  }
+
+  @Override
+  public void setY(long i, long v) {
+    array[(int)i*2+1] = (int)v;
+  }
+
+  @Override
+  public long size() {
+    return array.length/2;
+  }
+
+}

gui/fgfxFwt/java/fan/fgfxFwt/SwtUtil.java

+//
+// Copyright (c) 2011, chunquedong
+// Licensed under the Academic Free License version 3.0
+//
+// History:
+//   2011-09-09  Jed Young  Creation
+//
+package fan.fgfxFwt;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Transform;
+import org.eclipse.swt.widgets.Display;
+
+import fan.fgfxMath.Transform2D;
+import fan.fgfx2d.*;
+
+public class SwtUtil {
+
+  static Display getDisplay() {
+    return Display.getCurrent() == null ? new Display() : Display.getCurrent(); // SWT display
+  }
+
+  private static GC scratchGC = null;
+  public static GC scratchG() {
+    if (scratchGC == null) scratchGC = new GC(getDisplay());
+    return scratchGC;
+  }
+
+  public static org.eclipse.swt.graphics.Font toFont(Font f) {
+    if (f == null) return null;
+    int style = SWT.NORMAL;
+    if (f.bold) style |= SWT.BOLD;
+    if (f.italic) style |= SWT.ITALIC;
+    return new org.eclipse.swt.graphics.Font(getDisplay(), f.name, (int)f.size, style);
+  }
+
+  static public Transform toSwtTransform(Transform2D trans)
+  {
+    return new Transform(getDisplay(),
+       (float)trans.get(0,0),
+       (float)trans.get(0,1),
+       (float)trans.get(1,0),
+       (float)trans.get(1,1),
+       (float)trans.get(2,0),
+       (float)trans.get(2,1)
+       );
+  }
+
+  static public Transform2D toTransform(Transform trans) {
+    float[] elem = new float[6];
+    trans.getElements(elem);
+    Transform2D t = Transform2D.make();
+    t.set(0,0, elem[0]);
+    t.set(0,1, elem[1]);
+    t.set(1,0, elem[2]);
+    t.set(1,1, elem[3]);
+    t.set(2,0, elem[4]);
+    t.set(2,1, elem[5]);
+    return t;
+  }
+
+  static public org.eclipse.swt.graphics.Path toSwtPath(Path path)
+  {
+    int size = (int)path.steps().size();
+    org.eclipse.swt.graphics.Path swtPath = new org.eclipse.swt.graphics.Path(getDisplay());
+    for (int i =0; i < size; ++i)
+    {
+      PathStep step = (PathStep)path.steps().get(i);
+
+      if (step instanceof PathMoveTo)
+      {
+        PathMoveTo s = (PathMoveTo)step;
+        swtPath.moveTo((float)s.x, (float)s.y);
+      }
+      else if (step instanceof PathLineTo)
+      {
+        PathLineTo s = (PathLineTo)step;
+        swtPath.lineTo((float)s.x, (float)s.y);
+      }
+      else if (step instanceof PathQuadTo)
+      {
+        PathQuadTo s = (PathQuadTo)step;
+        swtPath.quadTo((float)s.cx, (float)s.cy, (float)s.x, (float)s.y);
+      }
+      else if (step instanceof PathCubicTo)
+      {
+        PathCubicTo s = (PathCubicTo)step;
+        swtPath.cubicTo((float)s.cx1, (float)s.cy1, (float)s.cx2, (float)s.cy2, (float)s.x, (float)s.y);
+      }
+      else if (step instanceof PathClose)
+      {
+        swtPath.close();
+      }
+      else
+      {
+        throw fan.sys.Err.make("unreachable");
+      }
+    }
+    return swtPath;
+  }
+
+  static java.awt.AlphaComposite toAwtComposite(fan.fgfx2d.Composite com, float alpha) {
+    int rule = 0;
+    if (com == fan.fgfx2d.Composite.srcAtop) {
+      rule = java.awt.AlphaComposite.SRC_ATOP;
+    } else if (com == fan.fgfx2d.Composite.srcIn) {
+      rule = java.awt.AlphaComposite.SRC_IN;
+    } else if (com == fan.fgfx2d.Composite.srcOut) {
+      rule = java.awt.AlphaComposite.SRC_OUT;
+    } else if (com == fan.fgfx2d.Composite.dstAtop) {
+      rule = java.awt.AlphaComposite.DST_ATOP;
+    } else if (com == fan.fgfx2d.Composite.dstIn) {
+      rule = java.awt.AlphaComposite.DST_IN;
+    } else if (com == fan.fgfx2d.Composite.dstOut) {
+      rule = java.awt.AlphaComposite.DST_OUT;
+    } else if (com == fan.fgfx2d.Composite.dstOver) {
+      rule = java.awt.AlphaComposite.DST_OVER;
+    } else if (com == fan.fgfx2d.Composite.lighter) {
+      return null;
+    } else if (com == fan.fgfx2d.Composite.copy) {
+      rule = java.awt.AlphaComposite.SRC;
+    } else if (com == fan.fgfx2d.Composite.xor) {
+      rule = java.awt.AlphaComposite.XOR;
+    } else if (com == fan.fgfx2d.Composite.clear) {
+      rule = java.awt.AlphaComposite.CLEAR;
+    } else {
+      return null;
+    }
+
+    return java.awt.AlphaComposite.getInstance(rule, alpha);
+  }
+
+  static org.eclipse.swt.graphics.Color toSwtColor(Color c)
+  {
+    int argb = (int)(c).argb;
+    return new org.eclipse.swt.graphics.Color(SwtUtil.getDisplay(), (argb >> 16) & 0xff, (argb >> 8) & 0xff, argb & 0xff);
+  }
+
+  static org.eclipse.swt.graphics.Image toSwtImage(Image image) {
+    org.eclipse.swt.graphics.Image img = null;
+    if (image instanceof SwtImage) {
+      img = ((SwtImage) image).getImage();
+    } else if (image instanceof SwtConstImage) {
+      img = ((SwtConstImage) image).getImage();
+    }
+    return img;
+  }
+}

gui/fgfxFwt/java/fan/fgfxWtk/FwtToolkitEnvPeer.java

-//
-// Copyright (c) 2011, chunquedong
-// Licensed under the Academic Free License version 3.0
-//
-// History:
-//   2011-7-4  Jed Young  Creation
-//
-
-package fan.fgfxWtk;
-
-import fan.concurrent.Actor;
-import fan.fgfx2d.Graphics;
-import fan.sys.*;
-
-public class FwtToolkitEnvPeer
-{
-  public static FwtToolkitEnvPeer make(ToolkitEnv self)
-  {
-    FwtToolkitEnvPeer peer = new FwtToolkitEnvPeer();
-    return peer;
-  }
-
-  public static void initGfxEnv()
-  {
-    Actor.locals().set("fgfx2d.env", SwtGfxEnv.instance);
-  }
-
-  public static Graphics toGraphics(fan.gfx.Graphics fg)
-  {
-    fan.fwt.FwtGraphics fwt = (fan.fwt.FwtGraphics)fg;
-    return new SwtGraphics(fwt.gc());
-  }
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtConstImage.java

-package fan.fgfxWtk;
-
-
-import org.eclipse.swt.graphics.Rectangle;
-
-import fan.fgfx2d.ConstImage;
-import fan.fgfx2d.Size;
-
-public class SwtConstImage implements ConstImage{
-
-  private org.eclipse.swt.graphics.Image image;
-  
-  public org.eclipse.swt.graphics.Image getImage(){ return image; };
-
-  SwtConstImage(org.eclipse.swt.graphics.Image image) {
-    this.image = image;
-  }
-
-  @Override
-  public Size size() {
-    Rectangle r = image.getBounds();
-    return Size.make(r.width, r.height);
-  }
-
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtFont.java

-package fan.fgfxWtk;
-
-import fan.sys.Func;
-
-import org.eclipse.swt.graphics.GC;
-
-import fan.fgfx2d.*;
-
-public class SwtFont extends Font {
-
-  private org.eclipse.swt.graphics.Font nfont = null;
-  private org.eclipse.swt.graphics.FontMetrics fontMetrics = null;
-
-  public static Font makeAwtFont(Func func)
-  {
-    Font f = new SwtFont();
-    func.enterCtor(f);
-    func.call(f);
-    func.exitCtor();
-    return f;
-  }
-
-  public org.eclipse.swt.graphics.Font getNFont() {
-    if (nfont == null) {
-      nfont = SwtUtil.toFont(this);
-    }
-    return nfont;
-  }
-
-  private GC scratchGC()
-  {
-    GC gc = SwtUtil.scratchG();
-    gc.setFont(nfont);
-    return gc;
-  }
-
-  public org.eclipse.swt.graphics.FontMetrics getFontMetrics() {
-    if (fontMetrics == null) {
-      fontMetrics = scratchGC().getFontMetrics();
-    }
-    return fontMetrics;
-  }
-
-
-  @Override
-  public long ascent() {
-    return getFontMetrics().getAscent();
-  }
-
-  @Override
-  public long descent() {
-    return getFontMetrics().getDescent();
-  }
-
-  @Override
-  public void dispose() {
-  }
-
-  @Override
-  public long height() {
-    return getFontMetrics().getHeight();
-  }
-
-  @Override
-  public long leading() {
-    return getFontMetrics().getLeading();
-  }
-
-  @Override
-  public long width(String s) {
-    return scratchGC().textExtent(s).x;
-  }
-
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtGfxEnv.java

-//
-// Copyright (c) 2011, chunquedong
-// Licensed under the Academic Free License version 3.0
-//
-// History:
-//   2011-09-09  Jed Young  Creation
-//
-package fan.fgfxWtk;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-
-import fan.fgfx2d.*;
-import fan.sys.Func;
-import fan.sys.IOErr;
-import fan.sys.InStream;
-import fan.sys.SysInStream;
-import fan.sys.Uri;
-
-public class SwtGfxEnv extends GfxEnv {
-
-  static final SwtGfxEnv instance = new SwtGfxEnv();
-  private SwtGfxEnv() {}
-
-  @Override
-  public boolean contains(Path path, double x, double y) {
-    org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
-    return p.contains((float)x, (float)y, SwtUtil.scratchG(), false);
-  }
-
-  @Override
-  public Image fromUri(Uri uri, Func onLoad) {
-    if (uri.scheme().equals("http")) {
-      onLoad = (Func) onLoad.toImmutable();
-      SwtImage p = new SwtImage();
-      loadFromWeb(p, uri, onLoad);
-      return p;
-    }
-
-    InputStream jin = SysInStream.java(((fan.sys.File) uri.get()).in());
-    SwtImage p = new SwtImage();
-    streamToImage(jin, p);
-    onLoad.call(p);
-    return p;
-  }
-
-  public Image fromStream(InStream in)
-  {
-    InputStream jin = SysInStream.java(in);
-    SwtImage p = new SwtImage();
-    streamToImage(jin, p);
-    return p;
-  }
-
-  private static void loadFromWeb(final SwtImage p, final Uri uri,
-      final Func onLoad) {
-    new Thread(new Runnable() {
-      public void run() {
-        InputStream jin;
-        try {
-          URL requestUrl = new URL(uri.toStr());
-          URLConnection con = requestUrl.openConnection();
-          jin = con.getInputStream();
-        } catch (IOException e) {
-          throw IOErr.make(e);
-        }
-
-        streamToImage(jin, p);
-        onLoad.call(p);
-      }
-    }).start();
-  }
-
-  private static void streamToImage(InputStream jin, SwtImage p) {
-    org.eclipse.swt.graphics.Image image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), jin);
-    p.setImage(image);
-  }
-
-  @Override
-  public Image makeImage(Size size) {
-    org.eclipse.swt.graphics.Image image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), (int)size.w, (int)size.h);
-    SwtImage p = new SwtImage();
-    p.setImage(image);
-    return p;
-  }
-
-  @Override
-  public ConstImage makeConstImage(Uri uri) {
-    InputStream jin;
-
-    if (uri.scheme().equals("http")) {
-      try {
-        URL requestUrl = new URL(uri.toStr());
-        URLConnection con = requestUrl.openConnection();
-        jin = con.getInputStream();
-      } catch (IOException e) {
-        throw IOErr.make(e);
-      }
-    } else {
-      jin = SysInStream.java(((fan.sys.File) uri.get()).in());
-    }
-
-    org.eclipse.swt.graphics.Image image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), jin);
-    try{
-      jin.close();
-     } catch (IOException e) {}
-    return new SwtConstImage(image);
-  }
-
-  @Override
-  public Font makeFont(Func func) {
-    return SwtFont.makeAwtFont(func);
-  }
-
-  @Override
-  public PointArray makePointArray(long size) {
-    PointArray pa = new SwtPointArray((int)size);
-    return pa;
-  }
-
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtGraphics.java

-//
-// Copyright (c) 2011, chunquedong
-// Licensed under the Academic Free License version 3.0
-//
-// History:
-//   2011-09-09  Jed Young  Creation
-//
-package fan.fgfxWtk;
-
-import java.util.Stack;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Pattern;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.graphics.Region;
-import org.eclipse.swt.graphics.Transform;
-import org.eclipse.swt.events.PaintEvent;
-
-import fan.fgfxMath.Transform2D;
-import fan.fgfx2d.*;
-import fan.sys.ArgErr;
-import fan.sys.FanObj;
-
-public class SwtGraphics implements Graphics {
-  
-  GC gc;
-  Pen pen = Pen.defVal;
-  Brush brush = Color.black;
-  Font font;
-  int alpha = 255;
-  Stack<State> stack = new Stack<State>();
-  
-  public SwtGraphics(PaintEvent e)
-  {
-    this(e.gc, e.x, e.y, e.width, e.height);
-  }
-  
-  public SwtGraphics(GC gc)
-  {
-    this.gc = gc;
-  }
-
-  public SwtGraphics(GC gc, int x, int y, int w, int h)
-  {
-    this.gc = gc;
-    clip(Rect.make(x, y, w, h));
-  }
-
-  public Brush brush()
-  {
-    return brush;
-  }
-
-  public void brush(Brush brush)
-  {
-    this.brush = brush;
-    Pattern oldfg = gc.getForegroundPattern();
-    Pattern oldbg = gc.getBackgroundPattern();
-    try
-    {
-      if (brush instanceof Color)
-      {
-        int ca = (int)((Color)brush).a();
-        gc.setAlpha((alpha == 255) ? ca : (int)((alpha * ca) / 255));
-        
-        org.eclipse.swt.graphics.Color c  = SwtUtil.toSwtColor((Color)brush);
-        gc.setForeground(c);
-        gc.setBackground(c);
-        gc.setForegroundPattern(null);
-        gc.setBackgroundPattern(null);
-      }
-      else if (brush instanceof Gradient)
-      {
-        // can't really map SWT model to CSS model well
-        Pattern p = pattern((Gradient)brush, 0, 0, 100, 100);
-        gc.setForegroundPattern(p);
-        gc.setBackgroundPattern(p);
-      }
-      else if (brush instanceof fan.gfx.Pattern)
-      {
-        Pattern p = pattern((fan.fgfx2d.Pattern)brush);
-        gc.setForegroundPattern(p);
-        gc.setBackgroundPattern(p);
-      }
-      else
-      {
-        throw ArgErr.make("Unsupported brush type: " + FanObj.typeof(brush));
-      }
-    }
-    finally
-    {
-      if (oldfg != null) oldfg.dispose();
-      if (oldbg != null) oldbg.dispose();
-    }
-  }
-
-  private Pattern pattern(Gradient g, float vx, float vy, float vw, float vh)
-  {
-    // only support two gradient stops
-    GradientStop s1 = (GradientStop)g.stops.get(0);
-    GradientStop s2 = (GradientStop)g.stops.get(-1L);
-    boolean x1Percent = g.x1Unit == Gradient.percent;
-    boolean y1Percent = g.y1Unit == Gradient.percent;
-    boolean x2Percent = g.x2Unit == Gradient.percent;
-    boolean y2Percent = g.y2Unit == Gradient.percent;
-
-    // start
-    float x1 = vx + g.x1;
-    float y1 = vy + g.y1;
-    float x2 = vx + g.x2;
-    float y2 = vy + g.y2;
-
-    // handle percentages
-    if (x1Percent) x1 = vx + vw * g.x1/100f;
-    if (y1Percent) y1 = vy + vh * g.y1/100f;
-    if (x2Percent) x2 = vx + vw * g.x2/100f;
-    if (y2Percent) y2 = vy + vh * g.y2/100f;
-
-    // System.out.println(g + "[" + vx + "," + vy + "," + vw + "," + vh + "]");
-    // System.out.println("  => " + x1 + "," + y1 + "  " + x2 + "," + y2);
-
-    // alpha
-    int a1 = (int)s1.color.a();
-    int a2 = (int)s2.color.a();
-    if (alpha != 255)
-    {
-      a1 = (int)((alpha * a1) / 255);
-      a2 = (int)((alpha * a2) / 255);
-    }
-
-    return new Pattern(SwtUtil.getDisplay(),
-        x1, y1, x2, y2,
-        SwtUtil.toSwtColor(s1.color), a1,
-        SwtUtil.toSwtColor(s2.color), a2);
-  }
-
-  private Pattern pattern(fan.fgfx2d.Pattern p)
-  {
-    return new Pattern(SwtUtil.getDisplay(), SwtUtil.toSwtImage(p.image));
-  }
-
-  public Pen pen()
-  {
-    return pen;
-  }
-
-  public void pen(Pen pen)
-  {
-    this.pen = pen;
-    gc.setLineWidth((int)pen.width);
-    gc.setLineCap(penCap(pen.cap));
-    gc.setLineJoin(penJoin(pen.join));
-    gc.setLineDash(pen.dash != null ? pen.dash.toInts() : null);
-  }
-
-  private static int penCap(long cap)
-  {
-    if (cap == Pen.capSquare) return SWT.CAP_SQUARE;
-    if (cap == Pen.capButt)   return SWT.CAP_FLAT;
-    if (cap == Pen.capRound)  return SWT.CAP_ROUND;
-    throw new IllegalStateException("Invalid pen.cap " + cap);
-  }
-
-  private static int penJoin(long join)
-  {
-    if (join == Pen.joinMiter) return SWT.JOIN_MITER;
-    if (join == Pen.joinBevel) return SWT.JOIN_BEVEL;
-    if (join == Pen.joinRound) return SWT.JOIN_ROUND;
-    throw new IllegalStateException("Invalid pen.join " + join);
-  }
-
-  public Font font()
-  {
-    return font;
-  }
-
-  public void font(Font font)
-  {
-    this.font = font;
-    this.gc.setFont(((SwtFont)font).getNFont());
-  }
-
-  public boolean antialias()
-  {
-    return gc.getAntialias() == SWT.ON;
-  }
-
-  public void antialias(boolean on)
-  {
-    int val = on ? SWT.ON : SWT.OFF;
-    gc.setAntialias(val);
-    gc.setTextAntialias(val);
-  }
-
-  public long alpha()
-  {
-    return alpha;
-  }
-
-  public void alpha(long alpha)
-  {
-    this.alpha = (int)alpha;
-    brush(this.brush);
-  }
-
-  public Graphics drawLine(long x1, long y1, long x2, long y2)
-  {
-    gc.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
-    return this;
-  }
-
-  public Graphics drawRect(long x, long y, long w, long h)
-  {
-    gc.drawRectangle((int)x, (int)y, (int)w, (int)h);
-    return this;
-  }
-
-  public Graphics fillRect(long x, long y, long w, long h)
-  {
-    // this is one case where we optimize gradients for view rect
-    if (brush instanceof Gradient)
-    {
-      Pattern newbg = pattern((Gradient)brush, x, y, w, h);
-      Pattern oldbg = gc.getBackgroundPattern();
-      gc.setBackgroundPattern(newbg);
-      gc.fillRectangle((int)x, (int)y, (int)w, (int)h);
-      gc.setBackgroundPattern(oldbg);
-      newbg.dispose();
-    }
-    else
-    {
-      gc.fillRectangle((int)x, (int)y, (int)w, (int)h);
-    }
-    return this;
-  }
-
-  public Graphics drawRoundRect(long x, long y, long w, long h, long wArc, long hArc)
-  {
-    gc.drawRoundRectangle((int)x, (int)y, (int)w, (int)h, (int)wArc, (int)hArc);
-    return this;
-  }
-
-  public Graphics fillRoundRect(long x, long y, long w, long h, long wArc, long hArc)
-  {
-    // this is one case where we optimize gradients for view rect
-    if (brush instanceof Gradient)
-    {
-      Pattern newbg = pattern((Gradient)brush, x, y, w, h);
-      Pattern oldbg = gc.getBackgroundPattern();
-      gc.setBackgroundPattern(newbg);
-      gc.fillRoundRectangle((int)x, (int)y, (int)w, (int)h, (int)wArc, (int)hArc);
-      gc.setBackgroundPattern(oldbg);
-      newbg.dispose();
-    }
-    else
-    {
-      gc.fillRoundRectangle((int)x, (int)y, (int)w, (int)h, (int)wArc, (int)hArc);
-    }
-    return this;
-  }
-
-  public Graphics drawOval(long x, long y, long w, long h)
-  {
-    gc.drawOval((int)x, (int)y, (int)w, (int)h);
-    return this;
-  }
-
-  public Graphics fillOval(long x, long y, long w, long h)
-  {
-    gc.fillOval((int)x, (int)y, (int)w, (int)h);
-    return this;
-  }
-
-  public Graphics drawArc(long x, long y, long w, long h, long s, long a)
-  {
-    gc.drawArc((int)x, (int)y, (int)w, (int)h, (int)s, (int)a);
-    return this;
-  }
-
-  public Graphics fillArc(long x, long y, long w, long h, long s, long a)
-  {
-    gc.fillArc((int)x, (int)y, (int)w, (int)h, (int)s, (int)a);
-    return this;
-  }
-
-  public Graphics drawText(String text, long x, long y)
-  {
-    int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT;
-    gc.drawText(text, (int)x, (int)y, flags);
-    return this;
-  }
-
-  public Graphics drawImage(Image img, long x, long y)
-  {
-    gc.drawImage(SwtUtil.toSwtImage(img), (int)x, (int)y);
-    return this;
-  }
-
-  public Graphics copyImage(Image img, Rect s, Rect d)
-  {
-    gc.drawImage(SwtUtil.toSwtImage(img),
-      (int)s.x, (int)s.y, (int)s.w, (int)s.h,
-      (int)d.x, (int)d.y, (int)d.w, (int)d.h);
-    return this;
-  }
-
-  public Graphics clip(Rect r)
-  {
-    Rectangle a = gc.getClipping();
-    Rectangle b = new Rectangle((int)r.x, (int)r.y, (int)r.w, (int)r.h);
-    gc.setClipping(a.intersection(b));
-    return this;
-  }
-
-  public Rect clipBounds()
-  {
-    Rectangle a = gc.getClipping();
-    return Rect.make(a.x, a.y, a.width, a.height);
-  }
-
-  public void dispose()
-  {
-    gc.dispose();
-  }
-
-//////////////////////////////////////////////////////////////////////////
-// State
-//////////////////////////////////////////////////////////////////////////
-
-  public void push()
-  {
-    State s = new State();
-    s.pen   = pen;
-    s.brush = brush;
-    s.font  = font;
-    s.antialias = gc.getAntialias();
-    s.textAntialias = gc.getTextAntialias();
-    s.alpha = alpha;
-    s.transform = new Transform(gc.getDevice());
-    gc.getTransform(s.transform);
-    s.clip = gc.getClipping();
-    stack.push(s);
-  }
-
-  public void pop()
-  {
-    State s = (State)stack.pop();
-    alpha = s.alpha;
-    pen(s.pen);
-    brush(s.brush);
-    font(s.font);
-    gc.setAntialias(s.antialias);
-    gc.setTextAntialias(s.textAntialias);
-    gc.setTransform(s.transform);
-    s.transform.dispose();
-    gc.setClipping(s.clip);
-  }
-
-  static class State
-  {
-    Pen pen;
-    Brush brush;
-    Font font;
-    int antialias;
-    int textAntialias;
-    int alpha;
-    Transform transform;
-    Rectangle clip;
-  }
-
-  public SwtGraphics drawPath(Path path)
-  {
-    org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
-    gc.drawPath(p);
-    p.dispose();
-    return this;
-  }
-  public SwtGraphics fillPath(Path path)
-  {
-    org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
-    gc.fillPath(p);
-    p.dispose();
-    return this;
-  }
-
-  public SwtGraphics drawPolyline(PointArray list)
-  {
-    SwtPointArray pa = (SwtPointArray)list;
-    gc.drawPolyline(pa.array);
-    return this;
-  }
-  public SwtGraphics fillPolygon(PointArray list)
-  {
-    SwtPointArray pa = (SwtPointArray)list;
-    gc.fillPolygon(pa.array);
-    return this;
-  }
-
-  @Override
-  public Graphics drawPolygon(PointArray list) {
-    SwtPointArray pa = (SwtPointArray)list;
-    gc.drawPolygon(pa.array);
-    return this;
-  }
-  
-  @Override
-  public void transform(Transform2D trans) {
-    Transform t = SwtUtil.toSwtTransform(trans);
-    gc.setTransform(t);
-    t.dispose();
-  }
-
-  @Override
-  public Transform2D transform() {
-    Transform t = new Transform(SwtUtil.getDisplay());
-    gc.getTransform(t);
-    Transform2D trans = SwtUtil.toTransform(t);
-    t.dispose();
-    return trans;
-  }
-
-  public SwtGraphics clipPath(Path path)
-  {
-    if (!gc.isClipped())
-    {
-      org.eclipse.swt.graphics.Path p = SwtUtil.toSwtPath(path);
-      gc.setClipping(p);
-      p.dispose();
-      return this;
-    }
-
-    Region region  = new Region();
-    gc.getClipping(region);
-
-    gc.setClipping(SwtUtil.toSwtPath(path));
-    Region region2  = new Region();
-    gc.getClipping(region2);
-
-    region.intersect(region2);
-    gc.setClipping(region);
-    return this;
-  }
-
-  /**
-   * auto free resource
-   */
-  @Override
-  protected void finalize()
-  {
-    if (!gc.isDisposed()) gc.dispose();
-  }
-
-  @Override
-  public Composite composite() {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public void composite(Composite arg0) {
-    // TODO Auto-generated method stub
-    
-  }
-
-  public GC gc() { return this.gc; }
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtImage.java

-//
-// Copyright (c) 2011, chunquedong
-// Licensed under the Academic Free License version 3.0
-//
-// History:
-//   2011-08-18  Jed Young  Creation
-//
-
-package fan.fgfxWtk;
-
-import java.io.OutputStream;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.ImageData;
-import org.eclipse.swt.graphics.ImageLoader;
-
-import fan.fgfx2d.*;
-import fan.sys.MimeType;
-import fan.sys.OutStream;
-import fan.sys.UnsupportedErr;
-import fanx.interop.Interop;
-
-public class SwtImage implements BufImage {
-  private boolean imageChanged = false;
-  private boolean painted = false;
-  private boolean isLoaded = false;
-
-  private org.eclipse.swt.graphics.Image image;
-  private org.eclipse.swt.graphics.ImageData imageData;
-
-  public void setImage(org.eclipse.swt.graphics.Image m)
-  {
-    image = m;
-    imageData = m.getImageData();
-    isLoaded = true;
-  }
-  
-  public org.eclipse.swt.graphics.Image getImage()
-  {
-    if (!imageChanged) return image;
-    if (!isLoaded) return null;
-
-    //create new image
-    image.dispose();
-    image = new org.eclipse.swt.graphics.Image(SwtUtil.getDisplay(), imageData);
-    imageChanged = false;
-    return image;
-  }
-
-  public ImageData getImageData()
-  {
-    if (painted)
-    {
-      imageData = image.getImageData();
-      painted = false;
-    }
-    return imageData;
-  }
-
-  public Size size() {
-    return Size.make(imageData.width, imageData.height);
-  }
-
-  public long getPixel(long x, long y) {
-    ImageData data = getImageData();
-    return data.getPixel((int) x, (int) y);
-  }
-
-  public void setPixel(long x, long y, long value) {
-    ImageData data = getImageData();
-    data.setPixel((int)x, (int)y, (int)value);
-    imageChanged = true;
-  }
-
-  /**
-   * save image to outSteam
-   */
-  public void save(OutStream out, MimeType format)
-  {
-    ImageLoader loader = new ImageLoader();
-    loader.data = new ImageData[] { getImageData() };
-    OutputStream jout = Interop.toJava(out);
-
-    int swtFormat = SWT.IMAGE_PNG;
-    String subType = format.subType();
-    if (subType.equals("png")) swtFormat = SWT.IMAGE_PNG;
-    else if (subType.equals("gif")) swtFormat = SWT.IMAGE_GIF;
-    else if (subType.equals("jpeg")) swtFormat = SWT.IMAGE_JPEG;
-    else if (subType.equals("jpg")) swtFormat = SWT.IMAGE_JPEG;
-    else if (subType.equals("bmp")) swtFormat = SWT.IMAGE_BMP;
-    else if (subType.equals("tiff")) swtFormat = SWT.IMAGE_TIFF;
-    else if (subType.equals("ico")) swtFormat = SWT.IMAGE_ICO;
-    else throw UnsupportedErr.make("unsupported image type: "+subType);
-
-    loader.save(jout, swtFormat);
-  }
-
-  public void save(OutStream out) {
-    save(out, MimeType.forExt("png"));
-  }
-
-  public boolean isLoaded() {
-    return image != null;
-  }
-
-  /**
-   * get graphics context from image
-   */
-  public Graphics graphics() {
-    int w = (int)size().w;
-    int h = (int)size().h;
-    painted = true;
-    return new SwtGraphics(new GC(getImage()), 0, 0, w, h);
-  }
-
-  @Override
-  public void dispose() {
-    if (!image.isDisposed()) image.dispose();
-  }
-  
-  /**
-   * auto free resource
-   */
-  @Override
-  protected void finalize()
-  {
-    dispose();
-  }
-
-  @Override
-  public ConstImage toConst() {
-    throw UnsupportedErr.make();
-  }
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtPointArray.java

-package fan.fgfxWtk;
-
-import fan.fgfx2d.*;
-
-public class SwtPointArray implements PointArray {
-
-  public int[] array;
-
-  SwtPointArray(int size) {
-    array = new int[size+size];
-  }
-
-  @Override
-  public long getX(long i) {
-    return array[(int)i*2];
-  }
-
-  @Override
-  public void setX(long i, long v) {
-    array[(int)i*2] = (int)v;
-  }
-
-  @Override
-  public long getY(long i) {
-    return array[(int)i*2+1];
-  }
-
-  @Override
-  public void setY(long i, long v) {
-    array[(int)i*2+1] = (int)v;
-  }
-
-  @Override
-  public long size() {
-    return array.length/2;
-  }
-
-}

gui/fgfxFwt/java/fan/fgfxWtk/SwtUtil.java

-//
-// Copyright (c) 2011, chunquedong
-// Licensed under the Academic Free License version 3.0
-//
-// History:
-//   2011-09-09  Jed Young  Creation
-//
-package fan.fgfxWtk;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Transform;
-import org.eclipse.swt.widgets.Display;
-
-import fan.fgfxMath.Transform2D;
-import fan.fgfx2d.*;
-
-public class SwtUtil {
-
-  static Display getDisplay() { 
-    return Display.getCurrent() == null ? new Display() : Display.getCurrent(); // SWT display
-  }
-  
-  private static GC scratchGC = null;
-  public static GC scratchG() {
-    if (scratchGC == null) scratchGC = new GC(getDisplay());
-    return scratchGC;
-  }
-
-  public static org.eclipse.swt.graphics.Font toFont(Font f) {
-    if (f == null) return null;
-    int style = SWT.NORMAL;
-    if (f.bold) style |= SWT.BOLD;
-    if (f.italic) style |= SWT.ITALIC;
-    return new org.eclipse.swt.graphics.Font(getDisplay(), f.name, (int)f.size, style);
-  }
-
-  static public Transform toSwtTransform(Transform2D trans)
-  {
-    return new Transform(getDisplay(),
-       (float)trans.get(0,0),
-       (float)trans.get(0,1),
-       (float)trans.get(1,0),
-       (float)trans.get(1,1),
-       (float)trans.get(2,0),
-       (float)trans.get(2,1)
-       );
-  }
-
-  static public Transform2D toTransform(Transform trans) {
-    float[] elem = new float[6];
-    trans.getElements(elem);
-    Transform2D t = Transform2D.make();
-    t.set(0,0, elem[0]);
-    t.set(0,1, elem[1]);
-    t.set(1,0, elem[2]);
-    t.set(1,1, elem[3]);
-    t.set(2,0, elem[4]);
-    t.set(2,1, elem[5]);
-    return t;
-  }
-
-  static public org.eclipse.swt.graphics.Path toSwtPath(Path path)
-  {
-    int size = (int)path.steps().size();
-    org.eclipse.swt.graphics.Path swtPath = new org.eclipse.swt.graphics.Path(getDisplay());
-    for (int i =0; i < size; ++i)
-    {
-      PathStep step = (PathStep)path.steps().get(i);
-
-      if (step instanceof PathMoveTo)
-      {
-        PathMoveTo s = (PathMoveTo)step;
-        swtPath.moveTo((float)s.x, (float)s.y);
-      }
-      else if (step instanceof PathLineTo)
-      {
-        PathLineTo s = (PathLineTo)step;
-        swtPath.lineTo((float)s.x, (float)s.y);
-      }
-      else if (step instanceof PathQuadTo)
-      {
-        PathQuadTo s = (PathQuadTo)step;
-        swtPath.quadTo((float)s.cx, (float)s.cy, (float)s.x, (float)s.y);
-      }
-      else if (step instanceof PathCubicTo)
-      {
-        PathCubicTo s = (PathCubicTo)step;
-        swtPath.cubicTo((float)s.cx1, (float)s.cy1, (float)s.cx2, (float)s.cy2, (float)s.x, (float)s.y);
-      }
-      else if (step instanceof PathClose)
-      {
-        swtPath.close();
-      }
-      else
-      {
-        throw fan.sys.Err.make("unreachable