changeset 572:dcd7adb2c0fc

Merge from Android_Skia
author Thinker K.F. Li <thinker@branda.to>
date Wed, 09 Jun 2010 17:30:09 +0800
parents aa2b388fba4e (current diff) 13b15b7a463b (diff)
children a2faee809514
files
diffstat 69 files changed, 4629 insertions(+), 647 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/native_test/Android.mk	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := native_test
+LOCAL_STATIC_LIBRARIES := libmbfly
+LOCAL_SHARED_LIBRARIES := libsgl
+LOCAL_C_INCLUDES += $(call include-path-for,corecg) \
+	$(TARGET_OUT_HEADERS)/libmbfly
+LOCAL_SRC_FILES := native_test.cpp
+
+include $(BUILD_EXECUTABLE)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/native_test/native_test.cpp	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,44 @@
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+
+extern "C" {
+#include <mb.h>
+};
+
+void native_test(void) {
+    mbe_t *mbe1, *mbe2;
+    SkBitmap *bmap1, *bmap2;
+    redraw_man_t _rdman;
+    redraw_man_t *rdman = &_rdman;
+    coord_t *root;
+    shape_t *shape;
+    paint_t *paint;
+
+    bmap1 = new SkBitmap();
+    bmap1->setConfig(SkBitmap::kARGB_8888_Config, 300, 300);
+    mbe1 = mbe_create((mbe_surface_t *)bmap1);
+    bmap2 = new SkBitmap();
+    bmap2->setConfig(SkBitmap::kARGB_8888_Config, 300, 300);
+    mbe2 = mbe_create((mbe_surface_t *)bmap2);
+
+    redraw_man_init(rdman, mbe1, mbe2);
+    root = rdman_get_root(rdman);
+    shape = rdman_shape_path_new(rdman, "M 100 100 L 100 150 L 150 150 z");
+    paint = rdman_paint_color_new(rdman, 1, 0, 0, 1);
+    rdman_paint_stroke(rdman, paint, shape);
+    rdman_add_shape(rdman, shape, root);
+
+    rdman_shape_changed(rdman, shape);
+    rdman_paint_changed(rdman, paint);
+
+    rdman_redraw_all(rdman);
+
+    rdman_paint_free(rdman, paint);
+    rdman_shape_free(rdman, shape);
+    redraw_man_destroy(rdman);
+}
+
+int main(int argc, const char *argv[]) {
+    native_test();
+    return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/AndroidManifest.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.madbutterfly.android.examples.testpath"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <application android:label="@string/app_name">
+        <activity android:name=".testpath"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+	<uses-library android:name="org.madbutterfly" />
+    </application>
+</manifest> 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/build.properties	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,20 @@
+# This file is used to override default values used by the Ant build system.
+# 
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source-folder' for the location of your java source folder and
+#  'out-folder' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+# The name of your application package as defined in the manifest.
+# Used by the 'uninstall' rule.
+application-package=org.madbutterfly.android.examples.testpath
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/build.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="testpath" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contain the path to the SDK. It should *NOT* be checked in in Version
+         Control Systems. -->
+    <property file="local.properties"/>
+
+    <!-- The build.properties file can be created by you and is never touched
+         by the 'android' tool. This is the place to change some of the default property values
+         used by the Ant rules.
+         Here are some properties you may want to change/update:
+
+         application-package
+             the name of your application package as defined in the manifest. Used by the
+             'uninstall' rule.
+         source-folder
+             the name of the source folder. Default is 'src'.
+         out-folder
+             the name of the output folder. Default is 'bin'.
+
+         Properties related to the SDK location or the project target should be updated
+          using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your application and
+         should be checked in in Version Control Systems.
+
+         -->
+    <property file="build.properties"/>
+
+    <!-- The default.properties file is created and updated by the 'android' tool, as well
+         as ADT. 
+         This file is an integral part of the build system for your application and
+         should be checked in in Version Control Systems. -->
+    <property file="default.properties"/>
+
+    <!-- Custom Android task to deal with the project target, and import the proper rules.
+         This requires ant 1.6.0 or above. -->
+    <path id="android.antlibs">
+        <pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
+        <pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
+        <pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
+        <pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
+        <pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
+    </path>
+
+    <taskdef name="setup"
+        classname="com.android.ant.SetupTask"
+        classpathref="android.antlibs"/>
+
+    <!-- Execute the Android Setup task that will setup some properties specific to the target,
+         and import the build rules files.
+
+         The rules file is imported from
+            <SDK>/platforms/<target_platform>/templates/android_rules.xml
+
+         To customize some build steps for your project:
+         - copy the content of the main node <project> from android_rules.xml
+         - paste it in this build.xml below the <setup /> task.
+         - disable the import by changing the setup task below to <setup import="false" />
+         
+         This will ensure that the properties are setup correctly but that your customized
+         build steps are used.
+    -->
+    <setup />
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/default.properties	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must be checked in Version Control Systems.
+# 
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/local.properties	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk-location=/home/thinker/progm/Android/out/host/freebsd-x86/sdk/android-sdk_eng.thinker_freebsd-x86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/res/layout/main.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+<TextView  
+    android:layout_width="fill_parent" 
+    android:layout_height="wrap_content" 
+    android:text="Hello World, testpath"
+    />
+</LinearLayout>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/res/values/strings.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">testpath</string>
+</resources>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/src/org/madbutterfly/android/examples/testpath/testpath.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,59 @@
+package org.madbutterfly.android.examples.testpath;
+
+import android.app.Activity;
+import android.view.SurfaceHolder;
+import android.content.Context;
+import android.os.Bundle;
+import android.graphics.Canvas;
+import android.util.Log;
+import org.madbutterfly.MBView;
+import org.madbutterfly.redraw_man;
+import org.madbutterfly.coord;
+import org.madbutterfly.shape;
+import org.madbutterfly.paint;
+
+public class testpath extends Activity implements SurfaceHolder.Callback
+{
+    MBView main_view;
+    String TAG = "testpath";
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+	SurfaceHolder holder;
+	
+        // setContentView(R.layout.main);
+	main_view = new MBView(this);
+	holder = main_view.getHolder();
+	holder.addCallback(this);
+	setContentView(main_view);
+    }
+
+    public void surfaceChanged(SurfaceHolder holder, int format,
+			       int w, int h) {
+    }
+
+    public void surfaceCreated(SurfaceHolder holder) {
+	redraw_man rdman;
+	shape path;
+	coord _coord;
+	paint pnt;
+	
+	Log.v(TAG, "surfaceCreated enter");
+	rdman = main_view.get_rdman();
+	path = rdman.shape_path_new("M 100 100 L 150 100 L 150 150 z");
+	path.set_stroke_width(2);
+	_coord = rdman.get_root();
+	_coord.add_shape(path);
+	pnt = rdman.paint_color_new(1, 0, 1, 1);
+	pnt.stroke(path);
+	Log.v(TAG, "surfaceCreated before redraw");
+	rdman.redraw();
+	Log.v(TAG, "surfaceCreated leave");
+    }
+
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/tests/AndroidManifest.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="org.madbutterfly.android.examples.testpath.tests"
+          android:versionCode="1"
+          android:versionName="1.0">
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+    <!--
+    This declares that this application uses the instrumentation test runner targeting
+    the package of org.madbutterfly.android.examples.testpath.  To run the tests use the command:
+    "adb shell am instrument -w org.madbutterfly.android.examples.testpath.tests/android.test.InstrumentationTestRunner"
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="org.madbutterfly.android.examples.testpath"
+                     android:label="Tests for testpath"/>
+</manifest>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/tests/build.properties	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,20 @@
+# This file is used to override default values used by the Ant build system.
+# 
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source-folder' for the location of your java source folder and
+#  'out-folder' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
+# The name of your application package as defined in the manifest.
+# Used by the 'uninstall' rule.
+application-package=org.madbutterfly.android.examples.testpath
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/tests/build.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="testpath" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contain the path to the SDK. It should *NOT* be checked in in Version
+         Control Systems. -->
+    <property file="local.properties"/>
+
+    <!-- The build.properties file can be created by you and is never touched
+         by the 'android' tool. This is the place to change some of the default property values
+         used by the Ant rules.
+         Here are some properties you may want to change/update:
+
+         application-package
+             the name of your application package as defined in the manifest. Used by the
+             'uninstall' rule.
+         source-folder
+             the name of the source folder. Default is 'src'.
+         out-folder
+             the name of the output folder. Default is 'bin'.
+
+         Properties related to the SDK location or the project target should be updated
+          using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your application and
+         should be checked in in Version Control Systems.
+
+         -->
+    <property file="build.properties"/>
+
+    <!-- The default.properties file is created and updated by the 'android' tool, as well
+         as ADT. 
+         This file is an integral part of the build system for your application and
+         should be checked in in Version Control Systems. -->
+    <property file="default.properties"/>
+
+    <!-- Custom Android task to deal with the project target, and import the proper rules.
+         This requires ant 1.6.0 or above. -->
+    <path id="android.antlibs">
+        <pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
+        <pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
+        <pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
+        <pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
+        <pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
+    </path>
+
+    <taskdef name="setup"
+        classname="com.android.ant.SetupTask"
+        classpathref="android.antlibs"/>
+
+    <!-- Execute the Android Setup task that will setup some properties specific to the target,
+         and import the build rules files.
+
+         The rules file is imported from
+            <SDK>/platforms/<target_platform>/templates/android_rules.xml
+
+         To customize some build steps for your project:
+         - copy the content of the main node <project> from android_rules.xml
+         - paste it in this build.xml below the <setup /> task.
+         - disable the import by changing the setup task below to <setup import="false" />
+         
+         This will ensure that the properties are setup correctly but that your customized
+         build steps are used.
+    -->
+    <setup />
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/tests/default.properties	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must be checked in Version Control Systems.
+# 
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/tests/local.properties	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must *NOT* be checked in Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk-location=/home/thinker/progm/Android/out/host/freebsd-x86/sdk/android-sdk_eng.thinker_freebsd-x86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/examples/testpath/tests/src/org/madbutterfly/android/examples/testpath/testpathTest.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,21 @@
+package org.madbutterfly.android.examples.testpath;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * This is a simple framework for a test of an Application.  See
+ * {@link android.test.ApplicationTestCase ApplicationTestCase} for more information on
+ * how to write and extend Application tests.
+ * <p/>
+ * To run this test, you can type:
+ * adb shell am instrument -w \
+ * -e class org.madbutterfly.android.examples.testpath.testpathTest \
+ * org.madbutterfly.android.examples.testpath.tests/android.test.InstrumentationTestRunner
+ */
+public class testpathTest extends ActivityInstrumentationTestCase2<testpath> {
+
+    public testpathTest() {
+        super("org.madbutterfly.android.examples.testpath", testpath.class);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/Android.mk	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,33 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := mbfly-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+LOCAL_SRC_FILES := \
+	org/madbutterfly/_jni.java \
+	org/madbutterfly/MBView.java \
+	org/madbutterfly/redraw_man.java \
+	org/madbutterfly/coord.java \
+	org/madbutterfly/shape.java \
+	org/madbutterfly/paint.java \
+	org/madbutterfly/InvalidStateException.java
+
+include $(BUILD_JAVA_LIBRARY)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := mbfly-permissions.xml
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/mbfly-permissions.xml	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+	<library name="org.madbutterfly"
+		 file="/system/framework/mbfly-java.jar" />
+
+</permissions>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/InvalidStateException.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,12 @@
+package org.madbutterfly;
+
+import java.lang.Exception;
+
+public class InvalidStateException extends Exception {
+    public InvalidStateException() {
+	super();
+    }
+    public InvalidStateException(String msg) {
+	super(msg);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/MBView.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,77 @@
+package org.madbutterfly;
+
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Bitmap;
+import android.graphics.Paint;
+import android.graphics.Xfermode;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+
+public class MBView extends SurfaceView {
+    redraw_man rdman;
+    Canvas cr, backend;
+    Bitmap cr_bmap, backend_bmap;
+    Paint copy_pnt;
+    int w, h;
+    
+    public MBView(Context context) {
+	super(context);
+	Paint paint;
+	Xfermode mode;
+	
+	rdman = null;
+	cr = null;
+	backend = null;
+	
+	mode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
+	copy_pnt = new Paint();
+	copy_pnt.setXfermode(mode);
+	w = 100;
+	h = 100;
+    }
+    
+    public redraw_man get_rdman() {
+	if(rdman != null)
+	    return rdman;
+
+	w = getWidth();
+	h = getHeight();
+
+	cr_bmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+	cr = new Canvas(cr_bmap);
+	backend_bmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+	backend = new Canvas(backend_bmap);
+	
+	rdman = new redraw_man(cr, backend, this);
+
+	return rdman;
+    }
+
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+	this.w = w;
+	this.h = h;
+
+	if(rdman == null) {
+	    get_rdman();
+	    return;
+	}
+	
+	cr_bmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+	cr.setBitmap(cr_bmap);
+	backend_bmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+	backend.setBitmap(backend_bmap);
+    }
+
+    public void redraw() {
+	SurfaceHolder holder;
+	Canvas canvas;
+
+	holder = getHolder();
+	canvas = holder.lockCanvas();
+	canvas.drawBitmap(backend_bmap, 0, 0, copy_pnt);
+	holder.unlockCanvasAndPost(canvas);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/_jni.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,48 @@
+package org.madbutterfly;
+import android.graphics.Canvas;
+
+class _jni {
+    native static int redraw_man_new(Canvas cr, Canvas backend);
+    native static void redraw_man_free(int rdman);
+    native static int rdman_add_shape(int rdman, int shape, int coord);
+    native static int rdman_get_root(int rdman);
+    native static int rdman_redraw_all(int rdman);
+    native static int rdman_redraw_changed(int rdman);
+    native static int rdman_redraw_area(int rdman, float x, float y,
+					float w, float h);
+    native static void rdman_paint_fill(int rdman, int paint, int shape);
+    native static void rdman_paint_stroke(int rdman, int paint, int shape);
+    
+    /* coord_t */
+    native static int rdman_coord_new(int rdman, int parent);
+    native static void rdman_coord_free(int rdman, int coord);
+    native static void rdman_coord_subtree_free(int rdman, int coord);
+    native static void rdman_coord_changed(int rdman, int coord);
+    
+    /* shape_t */
+    native static void rdman_shape_changed(int rdman, int shape);
+    native static void rdman_shape_free(int rdman, int shape);
+    native static int rdman_shape_path_new(int rdman, String data);
+    native static void sh_set_stroke_width(int shape, float w);
+
+    /* paint_t */
+    native static int rdman_paint_color_new(int rdman, float r, float g,
+					    float b, float a);
+    native static int rdman_paint_free(int rdman, int paint);
+    native static void paint_color_set(int paint, float r, float g,
+				      float b, float a);
+    native static float[] paint_color_get(int paint);
+    native static int rdman_paint_linear_new(int rdman,
+					     float x1, float y1,
+					     float x2, float y2);
+    native static int paint_linear_stops(int paint, int n_stops, int stops);
+    native static int rdman_paint_radial_new(int rdman, float cx, float cy,
+					     float r);
+    native static int paint_radial_stops(int paint, int n_stops, int stops);
+    native static int paint_create_stops(float stops[][]);
+    native static int paint_free_stops(int stops);
+    
+    static {
+	System.loadLibrary("mbfly-jni");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/coord.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,34 @@
+package org.madbutterfly;
+
+import java.util.ArrayList;
+
+public class coord {
+    protected int addr;
+    redraw_man rdman;
+    public ArrayList children;
+    public ArrayList members;
+
+    public coord(redraw_man rdman, int addr) {
+	this.addr = addr;
+	this.rdman = rdman;
+	children = new ArrayList();
+	members = new ArrayList();
+    }
+
+    protected void invalid() {
+	addr = 0;
+    }
+
+    protected void finalize() {
+	if(addr != 0)
+	    _jni.rdman_coord_free(rdman._rdman_addr, addr);
+    }
+
+    public void add_shape(shape member) {
+	_jni.rdman_add_shape(rdman._rdman_addr, member.addr, addr);
+	members.add(member);
+	member.parent = this;
+	_jni.rdman_coord_changed(rdman._rdman_addr, addr);
+	_jni.rdman_shape_changed(rdman._rdman_addr, member.addr);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/paint.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,70 @@
+package org.madbutterfly;
+
+import java.util.ArrayList;
+
+public class paint {
+    protected int addr;
+    redraw_man rdman;
+    ArrayList members;
+
+    public paint(redraw_man rdman, int addr) {
+	this.addr = addr;
+	this.rdman = rdman;
+	members = new ArrayList();
+    }
+
+    protected void invalid() {
+	addr = 0;
+    }
+
+    protected void finalize() {
+	if(addr != 0)
+	    _jni.rdman_paint_free(rdman._rdman_addr, addr);
+    }
+
+    public void stroke(shape sh) {
+	no_stroke(sh);
+	
+	if(sh.fill != this)
+	    members.add(sh);
+
+	sh.stroke = this;
+	
+	_jni.rdman_paint_stroke(rdman._rdman_addr, addr, sh.addr);
+    }
+    
+    public void fill(shape sh) {
+	no_fill(sh);
+	
+	if(sh.stroke != this)
+	    members.add(sh);
+
+	sh.fill = this;
+	
+	_jni.rdman_paint_fill(rdman._rdman_addr, addr, sh.addr);
+    }
+
+    public boolean is_empty() {
+	return members.size() == 0;
+    }
+
+    public static void no_stroke(shape sh) {
+	int i;
+	
+	if(sh.stroke != null && sh.stroke != sh.fill) {
+	    i = sh.stroke.members.indexOf(sh);
+	    sh.stroke.members.remove(i);
+	}
+	sh.stroke = null;
+    }
+
+    public static void no_fill(shape sh) {
+	int i;
+	
+	if(sh.fill != null && sh.stroke != sh.fill) {
+	    i = sh.stroke.members.indexOf(sh);
+	    sh.stroke.members.remove(i);
+	}
+	sh.fill = null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/redraw_man.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,108 @@
+package org.madbutterfly;
+
+import android.graphics.Canvas;
+import android.view.SurfaceHolder;
+import java.util.ArrayList;
+
+public class redraw_man {
+    Canvas _cr, _backend;
+    int _rdman_addr;		// address of redraw_man_t
+    coord root;
+    ArrayList paints;
+    MBView _view;
+    
+    public redraw_man(Canvas cr, Canvas backend, MBView view) {
+	int addr;
+	
+	_view = view;
+	_cr = cr;
+	_backend = backend;
+	
+	_rdman_addr = _jni.redraw_man_new(cr, backend);
+	addr = _jni.rdman_get_root(_rdman_addr);
+	root = new coord(this, addr);
+	
+	paints = new ArrayList();
+    }
+
+    static void _invalid_subtree(coord subtree) {
+	int i, sz;
+	coord child;
+	shape member;
+
+	subtree.invalid();
+	
+	sz = subtree.members.size();
+	for(i = 0; i < sz; i ++) {
+	    member = (shape)subtree.members.get(i);
+	    member.invalid();
+	}
+
+	sz = subtree.children.size();
+	for(i = 0; i < sz; i++) {
+	    child = (coord)subtree.children.get(i);
+	    _invalid_subtree(child);
+	}
+    }
+
+    protected void finalize() {
+	int i, sz;
+	paint pnt;
+	
+	_invalid_subtree(root);
+	
+	/* invalid paints */
+	sz = paints.size();
+	for(i = 0; i < sz; i++) {
+	    pnt = (paint)paints.get(i);
+	    pnt.invalid();
+	}
+	
+	_jni.redraw_man_free(_rdman_addr);
+    }
+
+    public coord get_root() {
+	return root;
+    }
+
+    public coord coord_new(coord parent) {
+	int addr;
+	coord child;
+	
+	addr = _jni.rdman_coord_new(_rdman_addr, parent.addr);
+	child = new coord(this, addr);
+	parent.children.add(child);
+	
+	return child;
+    }
+
+    public void coord_free(coord obj) {
+	obj.finalize();
+	obj.invalid();
+    }
+
+    public shape shape_path_new(String pathdata) {
+	int addr;
+	shape new_shape;
+
+	addr = _jni.rdman_shape_path_new(_rdman_addr, pathdata);
+	new_shape = new shape(this, addr);
+
+	return new_shape;
+    }
+
+    public paint paint_color_new(float r, float g, float b, float a) {
+	int addr;
+	paint pnt;
+
+	addr = _jni.rdman_paint_color_new(_rdman_addr, r, g, b, a);
+	pnt = new paint(this, addr);
+	
+	return pnt;
+    }
+
+    public void redraw() {
+	_jni.rdman_redraw_all(_rdman_addr);
+	_view.redraw();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/java/org/madbutterfly/shape.java	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,28 @@
+package org.madbutterfly;
+
+public class shape {
+    protected int addr;
+    redraw_man rdman;
+    protected coord parent;
+    protected paint stroke, fill;
+
+    public shape(redraw_man rdman, int addr) {
+	this.addr = addr;
+	this.rdman = rdman;
+	this.parent = null;
+	stroke = fill = null;
+    }
+    
+    protected void invalid() {
+	addr = 0;
+    }
+    
+    protected void finalize() {
+	if(addr != 0)
+	    _jni.rdman_shape_free(rdman._rdman_addr, addr);
+    }
+
+    public void set_stroke_width(float w) {
+	_jni.sh_set_stroke_width(addr, w);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/jni/Android.mk	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libmbfly-jni
+LOCAL_SRC_FILES := mbfly.cpp
+LOCAL_SHARED_LIBRARIES := libcorecg libsgl libnativehelper libcutils
+LOCAL_STATIC_LIBRARIES := libmbfly
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/libmbfly \
+	$(call include-path-for,corecg) \
+	$(call include-path-for,libnativehelper)/nativehelper
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/jni/mbfly.cpp	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,226 @@
+#include <SkCanvas.h>
+
+#define DECL_C extern "C" {
+#define END_C }
+
+DECL_C
+
+#include <stdio.h>
+#include <mb.h>
+#include <jni.h>
+
+#define ASSERT(x)
+
+
+extern mbe_t *skia_mbe_create_by_canvas(SkCanvas *canvas);
+
+jint Java_org_madbutterfly__1jni_redraw_1man_1new(JNIEnv *env,
+						  jobject cls,
+						  jobject cr,
+						  jobject backend) {
+    jclass canvas_cls;
+    jfieldID fid;
+    SkCanvas *_cr, *_backend;
+    redraw_man_t *rdman;
+    mbe_t *mbe1, *mbe2;
+    
+    canvas_cls = env->GetObjectClass(cr);
+    fid = env->GetFieldID(canvas_cls, "mNativeCanvas", "I");
+    _cr = (SkCanvas *)env->GetIntField(cr, fid);
+    canvas_cls = env->GetObjectClass(backend);
+    fid = env->GetFieldID(canvas_cls, "mNativeCanvas", "I");
+    _backend = (SkCanvas *)env->GetIntField(backend, fid);
+
+    mbe1 = skia_mbe_create_by_canvas(_cr);
+    mbe2 = skia_mbe_create_by_canvas(_backend);
+    ASSERT(mbe1 != NULL && mbe2 != NULL);
+    
+    rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
+    ASSERT(rdman != NULL);
+    redraw_man_init(rdman, mbe1, mbe2);
+    
+    return (jint)rdman;
+}
+
+void Java_org_madbutterfly__1jni_redraw_1man_1free(JNIEnv *env,
+						   jobject cls,
+						   jint rdman) {
+    redraw_man_destroy((redraw_man_t *)rdman);
+    free((redraw_man_t *)rdman);
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1add_1shape(JNIEnv *env,
+						   jobject cls,
+						   jint rdman,
+						   jint shape,
+						   jint coord) {
+    jint r;
+    
+    r = rdman_add_shape((redraw_man_t *)rdman,
+			(shape_t *)shape,
+			(coord_t *)coord);
+    return r;
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1get_1root(JNIEnv *env,
+						  jobject cls,
+						  jint rdman) {
+    jint root;
+
+    root = (jint)rdman_get_root((redraw_man_t *)rdman);
+    return root;
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1redraw_1all(JNIEnv *env,
+						    jobject cls,
+						    jint rdman) {
+    jint r;
+
+    r = rdman_redraw_all((redraw_man_t *)rdman);
+    return r;
+}
+
+void Java_org_madbutterfly__1jni_rdman_1paint_1fill(JNIEnv *env,
+						    jobject cls,
+						    jint rdman,
+						    jint paint,
+						    jint shape) {
+    rdman_paint_fill((redraw_man_t *)rdman,
+		     (paint_t *)paint,
+		     (shape_t *)shape);
+}
+
+void Java_org_madbutterfly__1jni_rdman_1paint_1stroke(JNIEnv *env,
+						      jobject cls,
+						      jint rdman,
+						      jint paint,
+						      jint shape) {
+    rdman_paint_stroke((redraw_man_t *)rdman,
+		       (paint_t *)paint,
+		       (shape_t *)shape);
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1coord_1new(JNIEnv *env,
+						   jobject cls,
+						   jint rdman,
+						   jint parent) {
+    jint coord;
+
+    coord = (jint)rdman_coord_new((redraw_man_t *)rdman,
+				  (coord_t *)parent);
+    return coord;
+}
+
+void Java_org_madbutterfly__1jni_rdman_1coord_1free(JNIEnv *env,
+						    jobject cls,
+						    jint rdman,
+						    jint coord) {
+    rdman_coord_free((redraw_man_t *)rdman,
+		     (coord_t *)coord);
+}
+
+void Java_org_madbutterfly__1jni_rdman_1coord_1subtree_1free(JNIEnv *env,
+							     jobject cls,
+							     jint rdman,
+							     jint coord) {
+    rdman_coord_subtree_free((redraw_man_t *)rdman,
+			     (coord_t *)coord);
+}
+
+void Java_org_madbutterfly__1jni_rdman_1coord_1changed(JNIEnv *env,
+						       jobject cls,
+						       jint rdman,
+						       jint coord) {
+    rdman_coord_changed((redraw_man_t *)rdman,
+			(coord_t *)coord);
+}
+
+void Java_org_madbutterfly__1jni_rdman_1shape_1changed(JNIEnv *env,
+						       jobject cls,
+						       jint rdman,
+						       jint shape) {
+    rdman_shape_changed((redraw_man_t *)rdman,
+			(shape_t *)shape);
+}
+
+void Java_org_madbutterfly__1jni_rdman_1shape_1free(JNIEnv *env,
+						    jobject cls,
+						    jint rdman,
+						    jint shape) {
+    rdman_shape_free((redraw_man_t *)rdman,
+		     (shape_t *)shape);
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1shape_1path_1new(JNIEnv *env,
+							 jobject cls,
+							 jint rdman,
+							 jstring data) {
+    const char *str;
+    jint shape;
+
+    str = env->GetStringUTFChars(data, NULL);
+    shape = (jint)rdman_shape_path_new((redraw_man_t *)rdman, (char *)str);
+    env->ReleaseStringUTFChars(data, str);
+
+    return shape;
+}
+
+void Java_org_madbutterfly__1jni_sh_1set_1stroke_1width(JNIEnv *env,
+							       jobject cls,
+							       jint shape,
+							       jfloat w) {
+    sh_set_stroke_width((shape_t *)shape, w);
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1paint_1color_1new(JNIEnv *env,
+							  jobject cls,
+							  jint rdman,
+							  jfloat r, jfloat g,
+							  jfloat b, jfloat a) {
+    jint paint;
+
+    paint = (jint)rdman_paint_color_new((redraw_man_t *)rdman,
+					r, g, b, a);
+    return paint;
+}
+
+jint Java_org_madbutterfly__1jni_rdman_1paint_1free(JNIEnv *env,
+						    jobject cls,
+						    jint rdman,
+						    jint paint) {
+    jint r;
+
+    r = rdman_paint_free((redraw_man_t *)rdman,
+			 (paint_t *)paint);
+    return r;
+}
+
+void Java_org_madbutterfly__1jni_paint_1color_1set(JNIEnv *env,
+						   jobject cls,
+						   jint paint,
+						   jfloat r, jfloat g,
+						   jfloat b, jfloat a) {
+    paint_color_set((paint_t *)paint, r, g, b, a);
+}
+
+jfloatArray Java_org_madbutterfly__1jni_paint_1color_1get(JNIEnv *env,
+							  jobject cls,
+							  jint paint) {
+    co_comp_t r, g, b, a;
+    jfloat color[4];
+    jfloatArray result;
+
+    paint_color_get((paint_t *)paint, &r, &g, &b, &a);
+    color[0] = r;
+    color[1] = g;
+    color[2] = b;
+    color[3] = a;
+    
+    result = env->NewFloatArray(4);
+    env->SetFloatArrayRegion(result, 0, 4, color);
+
+    return result;
+}
+
+END_C
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/mb/Android.mk	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,63 @@
+LOCAL_PATH:= $(call my-dir)
+MB_LOCAL_PATH := $(LOCAL_PATH)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := MadButterfly
+LOCAL_CONFIGURE := $(LOCAL_PATH)/../../configure
+LOCAL_CONFIGURE_ARGS := --enable-skia --config-cache
+LOCAL_CFLAGS := -I$(shell pwd)/$(call include-path-for,corecg) \
+	-I$(shell pwd)/$(call include-path-for,corecg)/../effects/ \
+	-I$(shell pwd)/$(call include-path-for,frameworks-base) \
+	-I$(shell pwd)/$(call include-path-for,system-core)
+# LOCAL_CFLAGS += -O0 -g
+LOCAL_CONFIGURE_CACHE := config.cache
+
+include $(BUILD_AUTOCONF)
+
+MB_INTERMEDIATES:=$(strip $(intermediates))
+
+$(LOCAL_BUILT_MODULE): $(MB_INTERMEDIATES)/build/config.cache
+
+$(MB_INTERMEDIATES)/build/config.cache:
+	$(hide) mkdir -p $(MB_INTERMEDIATES)/build/;
+	cp $(strip $(MB_LOCAL_PATH))/config.cache $(MB_INTERMEDIATES)/build/
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libmbfly
+LOCAL_MODULE_SUFFIX:= .a
+LOCAL_SRC_FILES:= $(MB_INTERMEDIATES)/build/src/.libs/libmbfly.a
+LOCAL_MODULE_CLASS:= STATIC_LIBRARIES
+LOCAL_REQUIRED_MODULES:= MadButterfly
+LOCAL_COPY_HEADERS:= \
+		../../include/mb_prop.h \
+		../../include/mb_graph_engine.h \
+		../../include/mb_redraw_man.h \
+		../../include/mb.h \
+		../../include/mb_graph_engine_cairo.h \
+		../../include/mb_shapes.h \
+		../../include/mb_X_supp.h \
+		../../include/mb_graph_engine_skia.h \
+		../../include/mb_so.h \
+		../../include/mb_af.h \
+		../../include/mb_img_ldr.h \
+		../../include/mb_timer.h \
+		../../include/mb_ani_menu.h \
+		../../include/mb_obj.h \
+		../../include/mb_tools.h \
+		../../include/mb_animate.h \
+		../../include/mb_observer.h \
+		../../include/mb_types.h \
+		../../include/mb_basic_types.h \
+		../../include/mb_paint.h \
+		../../include/mbbutton.h
+LOCAL_COPY_HEADERS_TO:= libmbfly
+
+include $(BUILD_DUMMY)
+
+MB_LOCAL_COPY_HEADERS_TO:= $(LOCAL_COPY_HEADERS_TO)
+$(eval $(call copy-one-header,$(MB_INTERMEDIATES)/build/include/mb_config.h,$(TARGET_OUT_HEADERS)/$(MB_LOCAL_COPY_HEADERS_TO)/mb_config.h))
+all_copied_headers: $(TARGET_OUT_HEADERS)/$(MB_LOCAL_COPY_HEADERS_TO)/mb_config.h
+
+$(MB_INTERMEDIATES)/build/src/.libs/libmbfly.a: MadButterfly
+$(MB_INTERMEDIATES)/build/include/mb_config.h: MadButterfly
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Android/mb/config.cache	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,121 @@
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+ac_cv_build=${ac_cv_build=i386-unknown-freebsd9.0}
+ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu=yes}
+ac_cv_c_const=${ac_cv_c_const=yes}
+ac_cv_c_uint32_t=${ac_cv_c_uint32_t=yes}
+ac_cv_c_uint64_t=${ac_cv_c_uint64_t=yes}
+ac_cv_cxx_compiler_gnu=${ac_cv_cxx_compiler_gnu=yes}
+ac_cv_env_CCC_set=''
+ac_cv_env_CCC_value=''
+ac_cv_env_CPPFLAGS_set=''
+ac_cv_env_CPPFLAGS_value=''
+ac_cv_env_CPP_set=''
+ac_cv_env_CPP_value=''
+ac_cv_env_CXXCPP_set=''
+ac_cv_env_CXXCPP_value=''
+ac_cv_env_LDFLAGS_set=set
+ac_cv_env_LDFLAGS_value=''
+ac_cv_env_LIBS_set=''
+ac_cv_env_LIBS_value=''
+ac_cv_env_PKG_CONFIG_set=''
+ac_cv_env_PKG_CONFIG_value=''
+ac_cv_env_XMKMF_set=''
+ac_cv_env_XMKMF_value=''
+ac_cv_env_build_alias_set=''
+ac_cv_env_build_alias_value=''
+ac_cv_env_cairo_CFLAGS_set=''
+ac_cv_env_cairo_CFLAGS_value=''
+ac_cv_env_cairo_LIBS_set=''
+ac_cv_env_cairo_LIBS_value=''
+ac_cv_env_host_alias_set=set
+ac_cv_env_host_alias_value=i386-unknown-freebsd
+ac_cv_env_pangocairo_CFLAGS_set=''
+ac_cv_env_pangocairo_CFLAGS_value=''
+ac_cv_env_pangocairo_LIBS_set=''
+ac_cv_env_pangocairo_LIBS_value=''
+ac_cv_env_target_alias_set=set
+ac_cv_env_target_alias_value=arm-unknown-linux
+ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=yes}
+ac_cv_func_malloc_0_nonnull=${ac_cv_func_malloc_0_nonnull=yes}
+ac_cv_func_memset=${ac_cv_func_memset=yes}
+ac_cv_func_realloc_0_nonnull=${ac_cv_func_realloc_0_nonnull=yes}
+ac_cv_func_select=${ac_cv_func_select=yes}
+ac_cv_func_select_args=${ac_cv_func_select_args='int,fd_set *,struct timeval *'}
+ac_cv_func_sqrt=${ac_cv_func_sqrt=no}
+ac_cv_func_strdup=${ac_cv_func_strdup=yes}
+ac_cv_have_x=${ac_cv_have_x='have_x=yes	ac_x_includes='\''/usr/local/include'\''	ac_x_libraries='\''/usr/local/lib'\'}
+ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h=yes}
+ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=yes}
+ac_cv_header_memory_h=${ac_cv_header_memory_h=yes}
+ac_cv_header_stdc=${ac_cv_header_stdc=no}
+ac_cv_header_stdint_h=${ac_cv_header_stdint_h=yes}
+ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes}
+ac_cv_header_string_h=${ac_cv_header_string_h=yes}
+ac_cv_header_strings_h=${ac_cv_header_strings_h=yes}
+ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h=yes}
+ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h=yes}
+ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes}
+ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=yes}
+ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h=yes}
+ac_cv_header_time=${ac_cv_header_time=yes}
+ac_cv_header_unistd_h=${ac_cv_header_unistd_h=yes}
+ac_cv_host=${ac_cv_host=i386-unknown-freebsd}
+ac_cv_objext=${ac_cv_objext=o}
+ac_cv_path_EGREP=${ac_cv_path_EGREP='/usr/bin/grep -E'}
+ac_cv_path_FGREP=${ac_cv_path_FGREP='/usr/bin/grep -F'}
+ac_cv_path_GREP=${ac_cv_path_GREP=/usr/bin/grep}
+ac_cv_path_SED=${ac_cv_path_SED=/usr/bin/sed}
+ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'}
+ac_cv_prog_AWK=${ac_cv_prog_AWK=gawk}
+ac_cv_prog_CC=${ac_cv_prog_CC=/home/thinker/progm/Android/prebuilt/freebsd-x86/toolchain/arm-eabi-4.4.0/bin/arm-unknown-eabi-gcc}
+ac_cv_prog_CPP=${ac_cv_prog_CPP='/home/thinker/progm/Android/prebuilt/freebsd-x86/toolchain/arm-eabi-4.4.0/bin/arm-unknown-eabi-gcc -E'}
+ac_cv_prog_CXXCPP=${ac_cv_prog_CXXCPP='/home/thinker/progm/Android/prebuilt/freebsd-x86/toolchain/arm-eabi-4.4.0/bin/arm-unknown-eabi-g++ -E'}
+ac_cv_prog_STRIP=${ac_cv_prog_STRIP=strip}
+ac_cv_prog_ac_ct_AR=${ac_cv_prog_ac_ct_AR=ar}
+ac_cv_prog_ac_ct_DUMPBIN=${ac_cv_prog_ac_ct_DUMPBIN='link -dump -symbols'}
+ac_cv_prog_ac_ct_OBJDUMP=${ac_cv_prog_ac_ct_OBJDUMP=objdump}
+ac_cv_prog_ac_ct_RANLIB=${ac_cv_prog_ac_ct_RANLIB=ranlib}
+ac_cv_prog_ac_ct_STRIP=${ac_cv_prog_ac_ct_STRIP=strip}
+ac_cv_prog_cc_c89=${ac_cv_prog_cc_c89=''}
+ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes}
+ac_cv_prog_cxx_g=${ac_cv_prog_cxx_g=yes}
+ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set=yes}
+ac_cv_struct_tm=${ac_cv_struct_tm=time.h}
+ac_cv_type_size_t=${ac_cv_type_size_t=yes}
+am_cv_CC_dependencies_compiler_type=${am_cv_CC_dependencies_compiler_type=gcc3}
+am_cv_CXX_dependencies_compiler_type=${am_cv_CXX_dependencies_compiler_type=gcc3}
+lt_cv_deplibs_check_method=${lt_cv_deplibs_check_method=pass_all}
+lt_cv_file_magic_cmd=${lt_cv_file_magic_cmd='$MAGIC_CMD'}
+lt_cv_file_magic_test_file=${lt_cv_file_magic_test_file=''}
+lt_cv_ld_reload_flag=${lt_cv_ld_reload_flag=-r}
+lt_cv_nm_interface=${lt_cv_nm_interface='BSD nm'}
+lt_cv_objdir=${lt_cv_objdir=.libs}
+lt_cv_path_LD=${lt_cv_path_LD=/usr/home/thinker/progm/Android/prebuilt/freebsd-x86/toolchain/arm-eabi-4.4.0/arm-unknown-eabi/bin/ld}
+lt_cv_path_LDCXX=${lt_cv_path_LDCXX=/usr/home/thinker/progm/Android/prebuilt/freebsd-x86/toolchain/arm-eabi-4.4.0/arm-unknown-eabi/bin/ld}
+lt_cv_path_NM=${lt_cv_path_NM=no}
+lt_cv_prog_compiler_c_o=${lt_cv_prog_compiler_c_o=yes}
+lt_cv_prog_compiler_c_o_CXX=${lt_cv_prog_compiler_c_o_CXX=yes}
+lt_cv_prog_compiler_pic_works=${lt_cv_prog_compiler_pic_works=yes}
+lt_cv_prog_compiler_pic_works_CXX=${lt_cv_prog_compiler_pic_works_CXX=yes}
+lt_cv_prog_compiler_rtti_exceptions=${lt_cv_prog_compiler_rtti_exceptions=no}
+lt_cv_prog_compiler_static_works=${lt_cv_prog_compiler_static_works=no}
+lt_cv_prog_compiler_static_works_CXX=${lt_cv_prog_compiler_static_works_CXX=no}
+lt_cv_prog_gnu_ld=${lt_cv_prog_gnu_ld=yes}
+lt_cv_prog_gnu_ldcxx=${lt_cv_prog_gnu_ldcxx=yes}
+lt_cv_sys_global_symbol_pipe=${lt_cv_sys_global_symbol_pipe=''}
+test "${lt_cv_sys_global_symbol_to_c_name_address+set}" = set || lt_cv_sys_global_symbol_to_c_name_address='sed -n -e '\''s/^: \([^ ]*\) $/  {\"\1\", (void *) 0},/p'\'' -e '\''s/^[BCDEGRST]* \([^ ]*\) \([^ ]*\)$/  {"\2", (void *) \&\2},/p'\'
+test "${lt_cv_sys_global_symbol_to_c_name_address_lib_prefix+set}" = set || lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='sed -n -e '\''s/^: \([^ ]*\) $/  {\"\1\", (void *) 0},/p'\'' -e '\''s/^[BCDEGRST]* \([^ ]*\) \(lib[^ ]*\)$/  {"\2", (void *) \&\2},/p'\'' -e '\''s/^[BCDEGRST]* \([^ ]*\) \([^ ]*\)$/  {"lib\2", (void *) \&\2},/p'\'
+lt_cv_sys_global_symbol_to_cdecl=${lt_cv_sys_global_symbol_to_cdecl=''}
+lt_cv_sys_max_cmd_len=${lt_cv_sys_max_cmd_len=196608}
--- a/Makefile.am	Sun Nov 08 00:37:29 2009 +0800
+++ b/Makefile.am	Wed Jun 09 17:30:09 2010 +0800
@@ -2,3 +2,7 @@
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libmbfly.pc
 EXTRA_DIST = libmbfly.pc.in Doxyfile README.h
+
+if NODEJS
+  SUBDIRS += nodejs
+endif
--- a/configure.ac	Sun Nov 08 00:37:29 2009 +0800
+++ b/configure.ac	Wed Jun 09 17:30:09 2010 +0800
@@ -4,18 +4,15 @@
 AC_PREREQ(2.61)
 AC_INIT([MadButterfly],[0.0],[http://www.assembla.com/spaces/MadButterfly])
 AC_CONFIG_SRCDIR([README.h])
-AC_CONFIG_HEADER([config.h])
+AC_CONFIG_HEADER([config.h include/mb_config.h])
 AM_INIT_AUTOMAKE([foreign])
 
 # Checks for programs.
 AC_PROG_CC
+AC_PROG_CXX
 LT_INIT
 AC_PROG_LIBTOOL
 
-# Checks for libraries.
-PKG_CHECK_MODULES([cairo], [cairo >= 1.6], , AC_MSG_ERROR([cairo >= 1.6 not found]))
-PKG_CHECK_MODULES([pangocairo], [pangocairo >= 1.0], , AC_MSG_ERROR([pangocairo >= 1.0 not found]))
-
 # Checks for header files.
 AC_PATH_X
 AC_HEADER_STDC
@@ -36,7 +33,7 @@
 AC_CHECK_FUNCS([gettimeofday memset select sqrt strdup])
 
 AC_ARG_ENABLE([testcase],
-	[--enable-testcase	Enable testcase],
+	[  --enable-testcase	Enable testcase],
 [case "${enableval}" in
   yes) testcase=true ;;
   no) testcase=false ;;
@@ -45,19 +42,15 @@
 AM_CONDITIONAL([TESTCASE], [test x$testcase = xtrue])
 
 AC_ARG_ENABLE([sh_text],
-	[--disable-sh_text	Turn off sh_text],
+	[  --disable-sh_text	Turn off sh_text],
 [case "${enableval}" in
   yes) sh_text=true ;;
   no) sh_text=false ;;
   *) AC_MSG_ERROR([bad value ${enableval} for --disable-sh_text]) ;;
 esac],[sh_text=true])
-AM_CONDITIONAL([SH_TEXT], [test x$sh_text = xtrue])
-[if [ x"${sh_text}" = xtrue ]; then]
-AC_DEFINE([SH_TEXT])
-[fi]
 
 AC_ARG_ENABLE([sh_stext],
-	[--disable-sh_stext	Turn off sh_stext],
+	[  --disable-sh_stext	Turn off sh_stext],
 [case "${enableval}" in
   yes) sh_stext=true ;;
   no) sh_stext=false ;;
@@ -68,6 +61,63 @@
 AC_DEFINE([SH_STEXT])
 [fi]
 
+AC_ARG_ENABLE([X_supp],
+	[  --disable-X_supp	Turn off X backend],
+[case "${enableval}" in
+  yes) X_supp=true ;;
+  no) X_supp=false ;;
+  *) AC_MSG_ERROR([bad value ${enableval} for --disable-X_supp]) ;;
+esac],[X_supp=true])
+
+AC_ARG_ENABLE([skia],
+	[  --enable-skia	Turn on Skia instead of Cairo],
+[case "${enableval}" in
+  yes) skia=true ;;
+  no) skia=false ;;
+  *) AC_MSG_ERROR([bad value ${enableval} for --enable-skia]) ;;
+esac],[skia=false])
+AM_CONDITIONAL([SKIA_GRAPH_ENGINE], [test x$skia = xtrue])
+AM_CONDITIONAL([CAIRO_GRAPH_ENGINE], [test x$skia != xtrue])
+[if [ x"${skia}" = xtrue ]; then ]
+AC_DEFINE([SKIA_GRAPH_ENGINE])
+cairo=false
+[else]
+AC_DEFINE([CAIRO_GRAPH_ENGINE])
+cairo=true
+[fi]
+
+AC_ARG_ENABLE([nodejs],
+	[  --enable-nodejs	Turn on nodejs support],
+[case "${enableval}" in
+  yes) nodejs=true ;;
+  no) nodejs=false ;;
+  *) AC_MSG_ERROR([bad value ${enableval} for --enable-nodejs]) ;;
+esac],[nodejs=false])
+[if [ x"${nodejs}" = xtrue ]; then ]
+  AC_PATH_PROG([NODE_WAF], [node-waf])
+  AC_CHECK_PROG([has_node], [node], [true], [false])
+[fi]
+AM_CONDITIONAL([NODEJS], [test x"${nodejs}-${has_node}" = xtrue-true])
+
+# Define AM and AC variable for sh_text
+AM_CONDITIONAL([SH_TEXT], [test x$sh_text = xtrue -a x$cairo = xtrue])
+[if [ x"${sh_text}" = xtrue -a x$cairo = xtrue ]; then]
+AC_DEFINE([SH_TEXT])
+[fi]
+
+# Define AM and AC variable for X_supp
+AM_CONDITIONAL([X_SUPP],
+	 [test x$X_supp = xtrue -a x$cairo = xtrue])
+[if [ x"${X_supp}" = xtrue -a x"${cairo}" = xtrue ]; then]
+AC_DEFINE([X_SUPP])
+[fi]
+
+# Checks for libraries.
+[if [ x"${cairo}" = xtrue ]; then]
+PKG_CHECK_MODULES([cairo], [cairo >= 1.6], , AC_MSG_ERROR([cairo >= 1.6 not found]))
+PKG_CHECK_MODULES([pangocairo], [pangocairo >= 1.0], , AC_MSG_ERROR([pangocairo >= 1.0 not found]))
+[fi]
+
 AC_CONFIG_FILES([Makefile
                  libmbfly.pc
                  libmbfly-uninstalled.pc
@@ -81,9 +131,13 @@
                  src/Makefile
                  include/Makefile
                  inkscape/Makefile
+		 nodejs/Makefile
                  tools/Makefile])
 
 AH_TEMPLATE([SH_TEXT],[Enable sh_text object])
 AH_TEMPLATE([SH_STEXT],[Enable sh_stext object])
+AH_TEMPLATE([SKIA_GRAPH_ENGINE], [Enable Skia Graphic Engine])
+AH_TEMPLATE([CAIRO_GRAPH_ENGINE], [Enable Cairo Graphic Engine])
+AH_TEMPLATE([X_SUPP], [Enable X backend])
 
 AC_OUTPUT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dox/Android.h	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,124 @@
+/*! \page android Integrate MadButterfly with Android
+ *
+ * I think almost all technical guys know Android, the mobile OS
+ * project from Google.  Once I know Android, my first idea is it is
+ * cool if Android programmers can be powered by MadButterfly.
+ * MadButterfly is very feasible for a lot of programs running on
+ * devices that Android be targeted for.  This document is about how
+ * the MadButterfly is integrated with Android and power Android
+ * applications.
+ *
+ * \section android_jni Android Native Code
+ *
+ * Android applications are actually Java code running on Dalvik VM.
+ * Although, Java bytecode was translated into Dalvik bytecode.  JNI
+ * is the bridge of bytecode and native code.  Bytecode and native
+ * code can access each other through JNI interface.  So, we must
+ * implement a set of JNI native function as the channel for
+ * communication between Android applications and MadButterfly.
+ * Following image is how the MadButterfly integrated with the
+ * Android.
+ *
+ * \image html Android-int.png
+ *
+ * MB JNI is a set of JNI native static methods that expose
+ * MadButterfly functions to Java code.  Java application can call
+ * native static methods of MB JNI to access functions provided by
+ * MadButterfly.
+ *
+ * Android applications draw everything on Canvas obects (backed by a
+ * surface).  A canvas is actually a wrapper for a SkCanvas of Skia.
+ * Drawing on a Canvas object means drawing on a SkCanvas object.  To
+ * draw on the screen, MadButterfly draws on the SkCanvas.
+ *
+ * The idea is to make MadButterfly as a View of Android UI.
+ * SurfaceView is extended as MBView; the sub-type of View for showing
+ * graphics generated by MadButterfly.  The SurfaceView own a surface.
+ * The surface is passed to MadButterfly as a SurfaceHolder.  MB JNI
+ * can get Canvas objects from the SurfaceHolder, and get associated
+ * SkCanvas in turn.  With SkCanvas objects, MadButterfly can draw for
+ * the MBView object.
+ *
+ * \section android_mem Memory Management for Android JNI Interface
+ *
+ * Some memory allocated and returned by MadButterfly should be
+ * managed by the application.  These memory blocks should not be
+ * freed until they are no more used by MadButterfly engine.  It means
+ * Android applications reponsible for managing memory blocks.  To
+ * simplify implmentation of MB JNI, MB JNI always return the address
+ * of an allocated objects as a Java integer.  Java code should
+ * take care about these addresses, and call proper functions for
+ * freeing objects specified by addresses at right time.
+ *
+ * A Java side framework should be designed to easy the work of
+ * Android application programmers.  The framework should take care of
+ * tracking life-cycle of MadButterfly objects.  The namespace of the
+ * framework is 'org.madbutterfly'.
+ *
+ * \section android_jni _jni
+ * 
+ * org.madbutterfly._jni class is the placeholder to collect JNI
+ * native methods for all MadButterfly functions.  All methods of _jni
+ * are static.  A method usually maps to a MadButterfly function.  For
+ * example, rdman_coord_new() mapes to the MadButterfly function with
+ * the same name.
+ *
+ * The object returned by a MadButterfly function, for ex. returned
+ * value of rdman_coord_new(), is casted to a int, the address of the
+ * object.  So, type of an argument or return value of an object is
+ * declared as a int.  For example,
+ * \code
+ * class _jni {
+ *   native static int rdman_coord_new(void);
+ * }
+ * \endcode
+ * Java code should keep these integers carefully for maintaining
+ * life-cycle of objects.
+ *
+ * MadButterfly provides only initial function for some objects,
+ * application should allocate memory for these function by them-self.
+ * For these function, a new JNI native method are used instead of
+ * initial function.  The new JNI method is responsible for allocating
+ * memory and calling initial function.  For example, redraw_man_new()
+ * is defined as a JNI method instead of redraw_man_init().
+ * \code
+ *   native static int redraw_man_new(Canvas cr, Canvas backend);
+ * \endcode
+ * First argument, rdman, of redraw_man_init() is replaced by a int
+ * returned value of redraw_man_new().  cr and backend, mbe_t type by
+ * MadButterfly, are, now, Canvas type by the JNI native method.  The
+ * implementation of the JNI native mothod would retrieves the
+ * SkCanvas object, and casts it to mbe_t type.
+ *
+ * \section android_java_mb Java Likes MadButterfly
+ *
+ * Managing life-cycle for MadButterfly objects is not Java likes.
+ * To provie a Java style interface for MadButterfly, a framework to
+ * hide underlying life-cycle management is requried.  Life-cycle is
+ * one major responsibility of the framework, it should keep integers
+ * of addresses of objects and free the associated resources with
+ * correct JNI methods and at right time.
+ *
+ * For example, org.madbutterfly.redraw_man is the respective Java
+ * class of redraw_man_t of MadButterfly engine.  redraw_man has a
+ * private member variable redraw_man._rdman_addr.  It is the address
+ * of the respective redraw_man_t object of MadButterfly.  redraw_man
+ * would call _jni.redraw_man_destroy() to release associated
+ * resources and free the memory before it being recycled.  So,
+ * redraw_man.finalize() is defined for releasing resources.  It would
+ * be called before a redraw_man object being recycled.
+ *
+ * \section android_MBView MBView for Android MBView extends
+ *
+ * SurfaceView is a sub-class of View provided by Android.  MBView
+ * inherits SurfaceView to implement a View controlled by
+ * MadButterfly.  A MBView object owns a redraw_man, a.k.a
+ * redraw_man_t of MadButterfly.  Android application programmers
+ * works on redraw_man to manipulate MadButterfly and changes content
+ * showed by the MBView object.  Android applications call
+ * MBView.get_rdman() to retrieve the redraw_man object assocaited
+ * with a MBView object.  MadButterfly would draw the content of a
+ * redraw_man object on the surface, inherited from the SurfaceView
+ * class, associated with the MBView object.
+ *
+ */
--- a/examples/Makefile.am	Sun Nov 08 00:37:29 2009 +0800
+++ b/examples/Makefile.am	Wed Jun 09 17:30:09 2010 +0800
@@ -1,1 +1,3 @@
+if X_SUPP
 SUBDIRS = calculator svg2code_ex tank dynamic drag menu
+endif
--- a/examples/menu/filebrowser.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/examples/menu/filebrowser.c	Wed Jun 09 17:30:09 2010 +0800
@@ -69,21 +69,20 @@
 {
     redraw_man_t *rdman = MBAF_RDMAN(app);
     paint_t *paint, *old_paint;
-    paint_t *previewimg_paint;
     shape_t *obj = (shape_t *) MB_SPRITE_GET_OBJ(app->rootsprite, "previewimg");
     int w, h;
 
-    previewimg_paint =
-	(paint_t *)MB_SPRITE_GET_OBJ(app->rootsprite,
-					   "previewimg_paint_img");
     printf("Preview %s\n",path);
-    paint = rdman_img_ldr_load_paint(rdman, path);
+    paint = rdman_img_ldr_load_paint(rdman, path); /* return a cached
+						    * paint if the
+						    * path was loaded
+						    * before */
     if (paint) {
 	paint_image_get_size(paint, &w, &h);
 	printf("image %d %d\n",w, h);
 	old_paint = sh_get_fill(obj);
 	rdman_paint_fill(rdman, paint, obj);
-	if(old_paint != previewimg_paint)
+	if(old_paint != paint)
 	    rdman_paint_free(rdman, old_paint);
 	    
 	rdman_shape_changed(MBAF_RDMAN(app),obj);
Binary file img/Android-int.png has changed
--- a/include/Makefile.am	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/Makefile.am	Wed Jun 09 17:30:09 2010 +0800
@@ -1,4 +1,5 @@
 include_HEADERS = 	\
+	mb_config.h	\
 	mb_animate.h 	\
 	mb.h	 	\
 	mb_timer.h 	\
--- a/include/mb.h	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/mb.h	Wed Jun 09 17:30:09 2010 +0800
@@ -1,9 +1,13 @@
 #ifndef __MB_H_
 #define __MB_H_
 
+#include "mb_config.h"
+
 #include "mb_types.h"
 #include "mb_redraw_man.h"
+#ifdef X_SUPP
 #include "mb_X_supp.h"
+#endif
 #include "mb_animate.h"
 #include "mb_shapes.h"
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mb_basic_types.h	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,11 @@
+#ifndef __MB_BASIC_TYPES_H_
+#define __MB_BASIC_TYPES_H_
+
+typedef float co_aix;
+typedef float co_comp_t;
+typedef struct _grad_stop {
+    co_aix offset;
+    co_comp_t r, g, b, a;
+} grad_stop_t;
+
+#endif /* __MB_BASIC_TYPES_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mb_config.h.in	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,19 @@
+#ifndef __MB_CONFIG_H_
+#define __MB_CONFIG_H_
+
+/* Enable Cairo Graphic Engine */
+#undef CAIRO_GRAPH_ENGINE
+
+/* Enable Skia Graphic Engine */
+#undef SKIA_GRAPH_ENGINE
+
+/* Enable sh_text */
+#undef SH_TEXT
+
+/* Enable sh_stext */
+#undef SH_STEXT
+
+/* Enable X backend */
+#undef X_SUPP
+
+#endif /* __MB_CONFIG_H_ */
--- a/include/mb_graph_engine.h	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/mb_graph_engine.h	Wed Jun 09 17:30:09 2010 +0800
@@ -1,187 +1,13 @@
 #ifndef __MBE_H_
 #define __MBE_H_
-
-#include <stdio.h>
-#include <cairo.h>
-#include <cairo-xlib.h>
-#include "mb_img_ldr.h"
-
-/*! \defgroup mb_graph_engine MadButterfly Graphic Engine
- * @{
- */
-#define MBE_OPERATOR_CLEAR CAIRO_OPERATOR_CLEAR
-#define MBE_OPERATOR_SOURCE CAIRO_OPERATOR_SOURCE
-#define MBE_STATUS_SUCCESS CAIRO_STATUS_SUCCESS
-
-#define mbe_ft_font_face_create_for_pattern cairo_ft_font_face_create_for_pattern
-#define mbe_image_surface_create_from_png cairo_image_surface_create_from_png
-#define mbe_pattern_add_color_stop_rgba cairo_pattern_add_color_stop_rgba
-#define mbe_pattern_create_for_surface cairo_pattern_create_for_surface
-#define mbe_scaled_font_text_extents cairo_scaled_font_text_extents
-#define mbe_image_surface_get_stride cairo_image_surface_get_stride
-#define mbe_image_surface_get_height cairo_image_surface_get_height
-#define mbe_image_surface_get_width cairo_image_surface_get_width
-#define mbe_image_surface_get_data cairo_image_surface_get_data
-#define mbe_scaled_font_reference cairo_scaled_font_reference
-#define mbe_pattern_create_radial cairo_pattern_create_radial
-#define mbe_pattern_create_linear cairo_pattern_create_linear
-#define mbe_xlib_surface_create cairo_xlib_surface_create
-#define mbe_scaled_font_destroy cairo_scaled_font_destroy
-#define mbe_font_options_create cairo_font_options_create
-#define mbe_font_face_reference cairo_font_face_reference
-#define mbe_set_source_surface cairo_set_source_surface
-#define mbe_scaled_font_status cairo_scaled_font_status
-#define mbe_scaled_font_create cairo_scaled_font_create
-#define mbe_pattern_set_matrix cairo_pattern_set_matrix
-#define mbe_font_face_destroy cairo_font_face_destroy
-#define mbe_paint_with_alpha cairo_paint_with_alpha
-#define mbe_font_face_status cairo_font_face_status
-#define mbe_surface_destroy cairo_surface_destroy
-#define mbe_set_source_rgba cairo_set_source_rgba
-#define mbe_set_scaled_font cairo_set_scaled_font
-#define mbe_pattern_destroy cairo_pattern_destroy
-#define mbe_get_scaled_font cairo_get_scaled_font
-#define mbe_set_source_rgb cairo_set_source_rgb
-#define mbe_set_line_width cairo_set_line_width
-#define mbe_get_font_face cairo_get_font_face
-#define mbe_fill_preserve cairo_fill_preserve
-#define mbe_set_operator cairo_set_operator
-#define mbe_get_operator cairo_get_operator
-#define mbe_set_source cairo_set_source
-#define mbe_reset_clip cairo_reset_clip
-#define mbe_get_target cairo_get_target
-#define mbe_close_path cairo_close_path
-#define mbe_text_path cairo_text_path
-#define mbe_show_text cairo_show_text
-#define mbe_rectangle cairo_rectangle
-#define mbe_in_stroke cairo_in_stroke
-#define mbe_new_path cairo_new_path
-#define mbe_curve_to cairo_curve_to
-#define mbe_restore cairo_restore
-#define mbe_move_to cairo_move_to
-#define mbe_line_to cairo_line_to
-#define mbe_in_fill cairo_in_fill
-#define mbe_destroy cairo_destroy
-#define mbe_stroke cairo_stroke
-#define mbe_create cairo_create
-#define mbe_paint cairo_paint
-#define mbe_save cairo_save
-#define mbe_fill cairo_fill
-#define mbe_clip cairo_clip
-
-typedef cairo_text_extents_t mbe_text_extents_t;
-typedef cairo_font_options_t mbe_font_options_t;
-typedef cairo_scaled_font_t mbe_scaled_font_t;
-typedef cairo_font_face_t mbe_font_face_t;
-typedef cairo_operator_t mbe_operator_t;
-typedef cairo_surface_t mbe_surface_t;
-typedef cairo_pattern_t mbe_pattern_t;
-typedef cairo_status_t mbe_status_t;
-typedef cairo_matrix_t mbe_matrix_t;
-typedef cairo_t mbe_t;
-typedef float co_aix;
+#include <mb_config.h>
 
-static mbe_surface_t *
-mbe_image_surface_create_for_data(unsigned char *data,
-				  mb_img_fmt_t fmt,
-				  int width, int height,
-				  int stride) {
-    cairo_format_t _fmt;
-    
-    switch(fmt) {
-    case MB_IFMT_ARGB32:
-	_fmt = CAIRO_FORMAT_ARGB32;
-	break;
-    case MB_IFMT_RGB24:
-	_fmt = CAIRO_FORMAT_RGB24;
-	break;
-    case MB_IFMT_A8:
-	_fmt = CAIRO_FORMAT_A8;
-	break;
-    case MB_IFMT_A1:
-	_fmt = CAIRO_FORMAT_A1;
-	break;
-    default:
-	return NULL;
-    }
-    return cairo_image_surface_create_for_data(data, _fmt,
-					       width, height, stride);
-}
-
-static mb_img_fmt_t
-mbe_image_surface_get_format(mbe_surface_t *surface) {
-    cairo_format_t _fmt;
-    mb_img_fmt_t fmt;
-
-    _fmt = cairo_image_surface_get_format(surface);
-    switch(_fmt) {
-    case CAIRO_FORMAT_ARGB32:
-	fmt = MB_IFMT_ARGB32;
-	break;
-    case CAIRO_FORMAT_RGB24:
-	fmt = MB_IFMT_RGB24;
-	break;
-    case CAIRO_FORMAT_A8:
-	fmt = MB_IFMT_A8;
-	break;
-    case CAIRO_FORMAT_A1:
-	fmt = MB_IFMT_A1;
-	break;
-    default:
-	fmt = MB_IFMT_DUMMY;
-	break;
-    }
+#ifdef CAIRO_GRAPH_ENGINE
+#include <mb_graph_engine_cairo.h>
+#endif
 
-    return fmt;
-}
-
-static mbe_surface_t *
-mbe_image_surface_create(mb_img_fmt_t fmt, int width, int height) {
-    cairo_format_t _fmt;
-    
-    switch(fmt) {
-    case MB_IFMT_ARGB32:
-	_fmt = CAIRO_FORMAT_ARGB32;
-	break;
-    case MB_IFMT_RGB24:
-	_fmt = CAIRO_FORMAT_RGB24;
-	break;
-    case MB_IFMT_A8:
-	_fmt = CAIRO_FORMAT_A8;
-	break;
-    case MB_IFMT_A1:
-	_fmt = CAIRO_FORMAT_A1;
-	break;
-    default:
-	return NULL;
-    }
-    
-    return cairo_image_surface_create(_fmt, width, height);
-}
-
-static void
-mbe_transform(mbe_t *mbe, const co_aix matrix[6]) {
-    cairo_matrix_t cmtx;
-
-    cmtx.xx = matrix[0];
-    cmtx.xy = matrix[1];
-    cmtx.x0 = matrix[2];
-    cmtx.yx = matrix[3];
-    cmtx.yy = matrix[4];
-    cmtx.y0 = matrix[5];
-
-    cairo_transform(mbe, &cmtx);
-}
-
-static void
-mbe_arc(mbe_t *mbe, co_aix x, co_aix y, co_aix radius,
-	co_aix angle_start, co_aix angle_stop) {
-    if(angle_start <= angle_stop)
-	cairo_arc(mbe, x, y, radius, angle_start, angle_stop);
-    else
-	cairo_arc_negative(mbe, x, y, radius, angle_start, angle_stop);
-}
-
-/* @} */
+#ifdef SKIA_GRAPH_ENGINE
+#include <mb_graph_engine_skia.h>
+#endif
 
 #endif /* __MBE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mb_graph_engine_cairo.h	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,246 @@
+#ifndef __MB_GE_CAIRO_H_
+#define __MB_GE_CAIRO_H_
+
+#include <stdio.h>
+#include <cairo.h>
+#include <cairo-xlib.h>
+#include "mb_basic_types.h"
+#include "mb_img_ldr.h"
+
+/*! \defgroup mb_ge_cairo MadButterfly Graphic Engine with Cairo
+ * @{
+ */
+#define MBE_OPERATOR_CLEAR CAIRO_OPERATOR_CLEAR
+#define MBE_OPERATOR_SOURCE CAIRO_OPERATOR_SOURCE
+#define MBE_STATUS_SUCCESS CAIRO_STATUS_SUCCESS
+
+#define mbe_image_surface_create_from_png cairo_image_surface_create_from_png
+#define mbe_pattern_create_for_surface cairo_pattern_create_for_surface
+#define mbe_scaled_font_text_extents cairo_scaled_font_text_extents
+#define mbe_image_surface_get_stride cairo_image_surface_get_stride
+#define mbe_image_surface_get_height cairo_image_surface_get_height
+#define mbe_image_surface_get_width cairo_image_surface_get_width
+#define mbe_image_surface_get_data cairo_image_surface_get_data
+#define mbe_scaled_font_reference cairo_scaled_font_reference
+#define mbe_xlib_surface_create cairo_xlib_surface_create
+#define mbe_scaled_font_destroy cairo_scaled_font_destroy
+#define mbe_font_face_reference cairo_font_face_reference
+#define mbe_font_face_destroy cairo_font_face_destroy
+#define mbe_paint_with_alpha cairo_paint_with_alpha
+#define mbe_surface_destroy cairo_surface_destroy
+#define mbe_set_source_rgba cairo_set_source_rgba
+#define mbe_set_scaled_font cairo_set_scaled_font
+#define mbe_pattern_destroy cairo_pattern_destroy
+#define mbe_get_scaled_font cairo_get_scaled_font
+#define mbe_set_source_rgb cairo_set_source_rgb
+#define mbe_set_line_width cairo_set_line_width
+#define mbe_get_font_face cairo_get_font_face
+#define mbe_fill_preserve cairo_fill_preserve
+#define mbe_set_source cairo_set_source
+#define mbe_reset_clip cairo_reset_clip
+#define mbe_get_target cairo_get_target
+#define mbe_close_path cairo_close_path
+#define mbe_text_path cairo_text_path
+#define mbe_rectangle cairo_rectangle
+#define mbe_in_stroke cairo_in_stroke
+#define mbe_new_path cairo_new_path
+#define mbe_curve_to cairo_curve_to
+#define mbe_restore cairo_restore
+#define mbe_move_to cairo_move_to
+#define mbe_line_to cairo_line_to
+#define mbe_in_fill cairo_in_fill
+#define mbe_destroy cairo_destroy
+#define mbe_stroke cairo_stroke
+#define mbe_create cairo_create
+#define mbe_paint cairo_paint
+#define mbe_save cairo_save
+#define mbe_fill cairo_fill
+#define mbe_clip cairo_clip
+
+typedef cairo_text_extents_t mbe_text_extents_t;
+typedef cairo_scaled_font_t mbe_scaled_font_t;
+typedef cairo_font_face_t mbe_font_face_t;
+typedef cairo_surface_t mbe_surface_t;
+typedef cairo_pattern_t mbe_pattern_t;
+typedef cairo_t mbe_t;
+
+#define MB_MATRIX_2_CAIRO(cmtx, mtx) {		\
+	(cmtx).xx = (mtx)[0];			\
+	(cmtx).xy = (mtx)[1];			\
+	(cmtx).x0 = (mtx)[2];			\
+	(cmtx).yx = (mtx)[3];			\
+	(cmtx).yy = (mtx)[4];			\
+	(cmtx).y0 = (mtx)[5];			\
+}
+
+
+extern mbe_font_face_t * mbe_query_font_face(const char *family,
+					     int slant, int weight);
+extern void mbe_free_font_face(mbe_font_face_t *face);
+extern mbe_pattern_t *mbe_pattern_create_radial(co_aix cx0, co_aix cy0,
+						co_aix radius0,
+						co_aix cx1, co_aix cy1,
+						co_aix radius1,
+						grad_stop_t *stops,
+						int stop_cnt);
+extern mbe_pattern_t *mbe_pattern_create_linear(co_aix x0, co_aix y0,
+						co_aix x1, co_aix y1,
+						grad_stop_t *stops,
+						int stop_cnt);
+
+
+static void mbe_pattern_set_matrix(mbe_pattern_t *ptn,
+				   const co_aix matrix[6]) {
+    cairo_matrix_t cmtx;
+
+    MB_MATRIX_2_CAIRO(cmtx, matrix);
+    cairo_pattern_set_matrix(ptn, &cmtx);
+}
+
+static void mbe_clear(mbe_t *canvas) {
+    cairo_operator_t old_op;
+    
+    old_op = cairo_get_operator(canvas);
+    cairo_set_operator(canvas, CAIRO_OPERATOR_CLEAR);
+    cairo_paint(canvas);
+    cairo_set_operator(canvas, old_op);
+}
+
+static void mbe_copy_source(mbe_t *src, mbe_t *dst) {
+    cairo_operator_t saved_op;
+    cairo_surface_t *surf;
+    cairo_pattern_t *ptn;
+    
+    surf = cairo_get_target(src);
+    ptn = cairo_pattern_create_for_surface(surf);
+    cairo_set_source(src, ptn);
+    cairo_pattern_destroy(ptn);
+    saved_op = cairo_get_operator(dst);
+    cairo_set_operator(dst, CAIRO_OPERATOR_SOURCE);
+    cairo_paint(dst);
+    cairo_set_operator(dst, saved_op);
+}
+
+static mbe_scaled_font_t *
+mbe_scaled_font_create(mbe_font_face_t *face, co_aix fnt_mtx[6],
+		       co_aix ctm[6]) {
+    cairo_font_options_t *options;
+    mbe_scaled_font_t *scaled;
+    cairo_matrix_t cfnt_mtx, cctm;
+
+    options = cairo_font_options_create();
+    if(options == NULL)
+	return NULL;
+    
+    MB_MATRIX_2_CAIRO(cfnt_mtx, fnt_mtx);
+    MB_MATRIX_2_CAIRO(cctm, ctm);
+    scaled = cairo_scaled_font_create(face, &cfnt_mtx, &cctm, options);
+
+    cairo_font_options_destroy(options);
+    
+    return scaled;
+}
+
+static mbe_surface_t *
+mbe_image_surface_create_for_data(unsigned char *data,
+				  mb_img_fmt_t fmt,
+				  int width, int height,
+				  int stride) {
+    cairo_format_t _fmt;
+    
+    switch(fmt) {
+    case MB_IFMT_ARGB32:
+	_fmt = CAIRO_FORMAT_ARGB32;
+	break;
+    case MB_IFMT_RGB24:
+	_fmt = CAIRO_FORMAT_RGB24;
+	break;
+    case MB_IFMT_A8:
+	_fmt = CAIRO_FORMAT_A8;
+	break;
+    case MB_IFMT_A1:
+	_fmt = CAIRO_FORMAT_A1;
+	break;
+    default:
+	return NULL;
+    }
+    return cairo_image_surface_create_for_data(data, _fmt,
+					       width, height, stride);
+}
+
+static mb_img_fmt_t
+mbe_image_surface_get_format(mbe_surface_t *surface) {
+    cairo_format_t _fmt;
+    mb_img_fmt_t fmt;
+
+    _fmt = cairo_image_surface_get_format(surface);
+    switch(_fmt) {
+    case CAIRO_FORMAT_ARGB32:
+	fmt = MB_IFMT_ARGB32;
+	break;
+    case CAIRO_FORMAT_RGB24:
+	fmt = MB_IFMT_RGB24;
+	break;
+    case CAIRO_FORMAT_A8:
+	fmt = MB_IFMT_A8;
+	break;
+    case CAIRO_FORMAT_A1:
+	fmt = MB_IFMT_A1;
+	break;
+    default:
+	fmt = MB_IFMT_DUMMY;
+	break;
+    }
+
+    return fmt;
+}
+
+static mbe_surface_t *
+mbe_image_surface_create(mb_img_fmt_t fmt, int width, int height) {
+    cairo_format_t _fmt;
+    
+    switch(fmt) {
+    case MB_IFMT_ARGB32:
+	_fmt = CAIRO_FORMAT_ARGB32;
+	break;
+    case MB_IFMT_RGB24:
+	_fmt = CAIRO_FORMAT_RGB24;
+	break;
+    case MB_IFMT_A8:
+	_fmt = CAIRO_FORMAT_A8;
+	break;
+    case MB_IFMT_A1:
+	_fmt = CAIRO_FORMAT_A1;
+	break;
+    default:
+	return NULL;
+    }
+    
+    return cairo_image_surface_create(_fmt, width, height);
+}
+
+static void
+mbe_transform(mbe_t *mbe, const co_aix matrix[6]) {
+    cairo_matrix_t cmtx;
+
+    cmtx.xx = matrix[0];
+    cmtx.xy = matrix[1];
+    cmtx.x0 = matrix[2];
+    cmtx.yx = matrix[3];
+    cmtx.yy = matrix[4];
+    cmtx.y0 = matrix[5];
+
+    cairo_transform(mbe, &cmtx);
+}
+
+static void
+mbe_arc(mbe_t *mbe, co_aix x, co_aix y, co_aix radius,
+	co_aix angle_start, co_aix angle_stop) {
+    if(angle_start <= angle_stop)
+	cairo_arc(mbe, x, y, radius, angle_start, angle_stop);
+    else
+	cairo_arc_negative(mbe, x, y, radius, angle_start, angle_stop);
+}
+/* @} */
+
+#endif /* __MB_GE_CAIRO_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/mb_graph_engine_skia.h	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,122 @@
+#ifndef __MB_GE_SKIA_H_
+#define __MB_GE_SKIA_H_
+
+#include <stdio.h>
+#include "mb_basic_types.h"
+#include "mb_img_ldr.h"
+
+/*! \defgroup mb_ge_skia MadButterfly Graphic Engine with Skia
+ * @{
+ */
+#define MBE_OPERATOR_CLEAR 2
+#define MBE_OPERATOR_SOURCE 1
+#define MBE_STATUS_SUCCESS 0
+
+struct _mbe_text_extents_t {
+    co_aix x_bearing;
+    co_aix y_bearing;
+    co_aix width;
+    co_aix height;
+    co_aix x_advance;
+    co_aix y_advance;
+};
+struct _mbe_scaled_font_t;
+struct _mbe_font_face_t;
+struct _mbe_surface_t;
+struct _mbe_pattern_t;
+struct _mbe_t;
+
+typedef struct _mbe_text_extents_t mbe_text_extents_t;
+typedef struct _mbe_scaled_font_t mbe_scaled_font_t;
+typedef struct _mbe_font_face_t mbe_font_face_t;
+typedef struct _mbe_surface_t mbe_surface_t;
+typedef struct _mbe_pattern_t mbe_pattern_t;
+typedef struct _mbe_t mbe_t;
+
+extern mbe_pattern_t *mbe_pattern_create_for_surface(mbe_surface_t *surface);
+extern mbe_pattern_t *mbe_pattern_create_radial(co_aix cx0, co_aix cy0,
+						co_aix radius0,
+						co_aix cx1, co_aix cy1,
+						co_aix radius1,
+						grad_stop_t *stops,
+						int stop_cnt);
+extern mbe_pattern_t *mbe_pattern_create_linear(co_aix x0, co_aix y0,
+						co_aix x1, co_aix y1,
+						grad_stop_t *stops,
+						int stop_cnt);
+extern void mbe_pattern_set_matrix(mbe_pattern_t *ptn,
+				   const co_aix matrix[6]);
+extern void mbe_pattern_destroy(mbe_pattern_t *ptn);
+
+extern int mbe_image_surface_get_stride(mbe_surface_t *surface);
+extern int mbe_image_surface_get_height(mbe_surface_t *surface);
+extern int mbe_image_surface_get_width(mbe_surface_t *surface);
+extern unsigned char *mbe_image_surface_get_data(mbe_surface_t *surface);
+extern mbe_surface_t *mbe_image_surface_create_from_png(const char *filename);
+extern mbe_surface_t *
+mbe_image_surface_create_for_data(unsigned char *data,
+				  mb_img_fmt_t fmt,
+				  int width, int height,
+				  int stride);
+extern mb_img_fmt_t mbe_image_surface_get_format(mbe_surface_t *surface);
+extern mbe_surface_t *
+mbe_image_surface_create(mb_img_fmt_t fmt, int width, int height);
+
+extern mbe_scaled_font_t *mbe_scaled_font_reference(mbe_scaled_font_t *scaled);
+extern void mbe_scaled_font_destroy(mbe_scaled_font_t *scaled);
+extern mbe_font_face_t *mbe_font_face_reference(mbe_font_face_t *face);
+extern mbe_scaled_font_t *
+mbe_scaled_font_create(mbe_font_face_t *face, co_aix fnt_mtx[6],
+		       co_aix ctm[6]);
+extern mbe_scaled_font_t *mbe_get_scaled_font(mbe_t *canvas);
+extern void mbe_scaled_font_text_extents(mbe_scaled_font_t *scaled,
+					 const char *txt,
+					 mbe_text_extents_t *extents);
+
+extern void mbe_font_face_destroy(mbe_font_face_t *face);
+extern void mbe_paint_with_alpha(mbe_t *canvas, co_aix alpha);
+extern void mbe_surface_destroy(mbe_surface_t *surface);
+extern void mbe_set_source_rgba(mbe_t *canvas,
+				co_aix r, co_aix g, co_aix b, co_aix a);
+extern void mbe_set_scaled_font(mbe_t *canvas,
+				const mbe_scaled_font_t *scaled);
+extern void mbe_set_source_rgb(mbe_t *canvas, co_aix r, co_aix g, co_aix b);
+extern void mbe_set_line_width(mbe_t *canvas, co_aix width);
+extern mbe_font_face_t *mbe_get_font_face(mbe_t *canvas);
+extern void mbe_fill_preserve(mbe_t *canvas);
+extern void mbe_set_source(mbe_t *canvas, mbe_pattern_t *source);
+extern void mbe_reset_clip(mbe_t *canvas);
+extern mbe_surface_t *mbe_get_target(mbe_t *canvas);
+extern void mbe_close_path(mbe_t *canvas);
+extern void mbe_text_path(mbe_t *canvas, const char *txt);
+extern void mbe_rectangle(mbe_t *canvas, co_aix x, co_aix y,
+			  co_aix width, co_aix height);
+extern int mbe_in_stroke(mbe_t *canvas, co_aix x, co_aix y);
+extern void mbe_new_path(mbe_t *canvas);
+extern void mbe_curve_to(mbe_t *canvas, co_aix x1, co_aix y1,
+			 co_aix x2, co_aix y2,
+			 co_aix x3, co_aix y3);
+extern void mbe_restore(mbe_t *canvas);
+extern void mbe_move_to(mbe_t *canvas, co_aix x, co_aix y);
+extern void mbe_line_to(mbe_t *canvas, co_aix x, co_aix y);
+extern int mbe_in_fill(mbe_t *canvas, co_aix x, co_aix y);
+extern void mbe_stroke(mbe_t *canvas);
+extern mbe_t *mbe_create(mbe_surface_t *target);
+extern void mbe_destroy(mbe_t *canvas);
+extern void mbe_paint(mbe_t *canvas);
+extern void mbe_save(mbe_t *canvas);
+extern void mbe_fill(mbe_t *canvas);
+extern void mbe_clip(mbe_t *canvas);
+
+extern mbe_font_face_t * mbe_query_font_face(const char *family,
+					     int slant, int weight);
+extern void mbe_free_font_face(mbe_font_face_t *face);
+
+extern void mbe_clear(mbe_t *canvas);
+extern void mbe_copy_source(mbe_t *src, mbe_t *dst);
+extern void mbe_transform(mbe_t *mbe, co_aix matrix[6]);
+extern void mbe_arc(mbe_t *mbe, co_aix x, co_aix y, co_aix radius,
+		    co_aix angle_start, co_aix angle_stop);
+/* @} */
+
+#endif /* __MB_GE_SKIA_H_ */
--- a/include/mb_paint.h	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/mb_paint.h	Wed Jun 09 17:30:09 2010 +0800
@@ -7,8 +7,6 @@
 #include "mb_img_ldr.h"
 #include "mb_tools.h"
 
-typedef float co_comp_t;
-
 extern paint_t *rdman_paint_color_new(redraw_man_t *rdman,
 				      co_comp_t r, co_comp_t g,
 				      co_comp_t b, co_comp_t a);
@@ -30,11 +28,6 @@
 #define paint_destroy(_paint)
 
 
-typedef struct _grad_stop {
-    co_aix offset;
-    co_comp_t r, g, b, a;
-} grad_stop_t;
-
 extern paint_t *rdman_paint_linear_new(redraw_man_t *rdman,
 				       co_aix x1, co_aix y1,
 				       co_aix x2, co_aix y2);
--- a/include/mb_redraw_man.h	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/mb_redraw_man.h	Wed Jun 09 17:30:09 2010 +0800
@@ -55,6 +55,7 @@
     elmpool_t *coord_canvas_pool;
 
     coords_t dirty_coords;
+    coords_t dirty_pcache_area_coords;
     geos_t dirty_geos;
     int n_dirty_areas;		/*!< \brief Number of all dirty areas. */
 
@@ -109,8 +110,6 @@
     } while(0)
 extern int rdman_shape_free(redraw_man_t *rdman, shape_t *shape);
 
-#define rdman_paint_man(rdman, paint)		\
-    STAILQ_INS_TAIL(rdman->paints, paint_t, pnt_next, shape)
 extern int rdman_paint_free(redraw_man_t *rdman, paint_t *paint);
 
 extern coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent);
@@ -157,25 +156,31 @@
 #define _rdman_paint_remove_child(rdman, paint, shape)		\
     do {							\
 	if((shape)->fill == (shape)->stroke &&			\
-	   (shape)->stroke == paint)				\
+	   (shape)->stroke == (paint))				\
 	    break;						\
 	_rdman_paint_real_remove_child(rdman, paint, shape);	\
     } while(0)
-#define rdman_paint_fill(rdman, paint, shape)		\
-    do {						\
-	if((shape)->fill == paint)			\
-	    break;					\
-	_rdman_paint_remove_child(rdman, paint, shape);	\
-	_rdman_paint_child(rdman, paint, shape);	\
-	(shape)->fill = paint;				\
+#define rdman_paint_fill(rdman, paint, shape)			\
+    do {							\
+	if((shape)->fill == paint)				\
+	    break;						\
+	if((shape)->fill)					\
+	    _rdman_paint_remove_child(rdman, (shape)->fill,	\
+				      shape);			\
+	if(paint)						\
+	    _rdman_paint_child(rdman, paint, shape);		\
+	(shape)->fill = paint;					\
     } while(0)
-#define rdman_paint_stroke(rdman, paint, shape)		\
-    do {						\
-	if((shape)->stroke == paint)			\
-	    break;					\
-	_rdman_paint_remove_child(rdman, paint, shape);	\
-	_rdman_paint_child(rdman, paint, shape);	\
-	(shape)->stroke = paint;			\
+#define rdman_paint_stroke(rdman, paint, shape)			\
+    do {							\
+	if((shape)->stroke == paint)				\
+	    break;						\
+	if((shape)->stroke)					\
+	    _rdman_paint_remove_child(rdman, (shape)->stroke,	\
+				      shape);			\
+	if(paint)						\
+	    _rdman_paint_child(rdman, paint, shape);		\
+	(shape)->stroke = paint;				\
     } while(0)
 extern int rdman_paint_changed(redraw_man_t *rdman, paint_t *paint);
 
--- a/include/mb_shapes.h	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/mb_shapes.h	Wed Jun 09 17:30:09 2010 +0800
@@ -7,11 +7,16 @@
 #ifndef __SHAPES_H_
 #define __SHAPES_H_
 
+#include "mb_config.h"
+
+#ifdef SH_TEXT
+#include <pango/pangocairo.h>
+#endif
+
 #include "mb_graph_engine.h"
 #include "mb_types.h"
 #include "mb_redraw_man.h"
 #include "mb_img_ldr.h"
-#include <pango/pangocairo.h>
 
 /*! \page define_shape How to Define Shapes
  *
@@ -60,7 +65,7 @@
 /*! \defgroup shape_path Shape of Path
  * @{
  */
-extern shape_t *rdman_shape_path_new(redraw_man_t *rdman, char *data);
+extern shape_t *rdman_shape_path_new(redraw_man_t *rdman, const char *data);
 extern shape_t *rdman_shape_path_new_from_binary(redraw_man_t *rdman,
 						 char *commands,
 						 co_aix *pnts,
@@ -71,6 +76,7 @@
 extern void sh_path_draw(shape_t *shape, mbe_t *cr);
 /* @} */
 
+#ifdef SH_TEXT
 /*! \defgroup shape_text Shape of Text
  * @{
  */
@@ -92,6 +98,7 @@
 extern void sh_text_transform(shape_t *shape);
 extern void sh_text_draw(shape_t *shape, mbe_t *cr);
 /* @} */
+#endif
 
 /*! \defgroup mb_text_t Shape of Text
  * @{
--- a/include/mb_types.h	Sun Nov 08 00:37:29 2009 +0800
+++ b/include/mb_types.h	Wed Jun 09 17:30:09 2010 +0800
@@ -123,6 +123,7 @@
 #define GEF_HIDDEN 0x2		/*!< The geo is hidden. */
 #define GEF_FREE 0x4
 #define GEF_OV_DRAW 0x8		/*!< To flag drawed for a overlay testing. */
+#define GEF_SWAP 0x10
 
 extern int areas_are_overlay(area_t *r1, area_t *r2);
 extern void area_init(area_t *area, int n_pos, co_aix pos[][2]);
@@ -161,9 +162,10 @@
 				 */
     area_t aggr_dirty_areas[2];	/*!< Used to aggregate updates to parent. */
     area_t cached_dirty_area;	/*!< Used to dirty an area in cached space. */
-    area_t owner_mems_area;	/*!< \brief The area is covered by members
-				 * of owner.
-				 */
+    area_t pcache_areas[2];	/*!< The area in the space of parent
+                                 *   cached. */
+    area_t *pcache_cur_area;	/*!< Current area for parent cached. */
+    area_t *pcache_last_area;	/*!< Last area for parent cached. */
 } coord_canvas_info_t;
 
 /*! \brief A coordination system.
@@ -241,6 +243,16 @@
 				 * It is used by clean_rdman_dirties().
 				 */
 #define COF_TEMP_MARK 0x400	/*!< \brief Temporary mark a coord. */
+#define COF_JUST_ZERO 0x800	/*!< \brief The coord is real peformed zeroing.
+				 * 
+				 * It's canvas is changed by zeroing.
+				 */
+#define COF_DIRTY_PCACHE_AREA 0x1000 /*!< \brief pcache_area shoud be
+                                      *  updated.
+				      */
+#define COF_SKIP_ZERO 0x2000	/*!< \brief The coord just skip zeroing.
+				 * No real zeroing was performed.
+				 */
 /* @} */
 
 extern void matrix_mul(co_aix *m1, co_aix *m2, co_aix *dst);
@@ -251,6 +263,7 @@
 extern co_aix coord_trans_size(coord_t *co, co_aix size);
 extern void compute_aggr_of_coord(coord_t *coord);
 extern void compute_aggr_of_cached_coord(coord_t *coord);
+extern void compute_aggr(coord_t *coord);
 extern void compute_reverse(co_aix *orig, co_aix *reverse);
 extern void update_aggr_matrix(coord_t *start);
 extern coord_t *preorder_coord_subtree(coord_t *root, coord_t *last);
@@ -277,7 +290,7 @@
 	(co)->flags &= ~COF_CACHE_MASK;				\
     } while(0)
 #define coord_is_root(co) ((co)->parent == NULL)
-#define coord_is_cached(co) ((co)->flags & COF_CACHE_MASK)
+#define coord_is_cached(co) ((co)->flags & COF_OWN_CANVAS)
 #define coord_is_fast_cached(co) ((co)->flags & COF_FAST_MASK)
 #define coord_is_precise_cached(co) ((co)->flags & COF_PRECISE_MASK)
 #define coord_is_zeroing(co) ((co)->flags & COF_MUST_ZEROING)
@@ -287,11 +300,13 @@
     do { (co)->flags &= ~COF_MUST_ZEROING; } while(0)
 #define coord_set_flags(co, _flags)		\
     do { (co)->flags |= (_flags); } while(0)
+#define coord_get_parent(co) ((co)->parent)
 #define coord_get_flags(co, _flags) ((co)->flags & (_flags))
 #define coord_clear_flags(co, _flags)		\
     do { (co)->flags &= ~(_flags); } while(0)
 #define coord_get_mouse_event(coord) ((coord)->mouse_event)
 #define coord_get_aggr_matrix(coord) ((coord)->aggr_matrix)
+#define coord_get_matrix(coord) ((coord)->matrix)
 #define FOR_COORDS_POSTORDER(coord, cur)			\
     for((cur) = postorder_coord_subtree((coord), NULL);		\
 	(cur) != NULL;						\
@@ -323,12 +338,19 @@
 	shape = geo_get_shape_safe(STAILQ_NEXT(geo_t, coord_next,	\
 					       sh_get_geo(shape))))
 #define coord_get_area(coord) ((coord)->cur_area)
+#define coord_get_last_area(coord) ((coord)->last_area)
+#define coord_get_pcache_area(coord) ((coord)->canvas_info->pcache_cur_area)
+#define coord_get_pcache_last_area(coord)	\
+    ((coord)->canvas_info->pcache_last_area)
+#define coord_get_cached(coord) ((coord)->canvas_info->owner)
 #define _coord_get_canvas(coord) ((coord)->canvas_info->canvas)
 #define _coord_set_canvas(coord, _canvas)		\
     do {						\
 	(coord)->canvas_info->canvas = _canvas;		\
     } while(0)
 #define _coord_get_dirty_areas(coord) (&(coord)->canvas_info->dirty_areas)
+#define _coord_get_aggr_dirty_areas(coord)	\
+    ((coord)->canvas_info->aggr_dirty_areas)
 
 /* @} */
 
@@ -377,6 +399,8 @@
 #define sh_get_aggr_matrix(sh) (coord_get_aggr_matrix(sh_get_coord(sh)))
 #define sh_get_fill(sh) ((sh)->fill)
 #define sh_get_stroke(sh) ((sh)->stroke)
+#define sh_set_stroke_width(sh, v) do { (sh)->stroke_width = (v); } while(0)
+#define sh_get_stroke_width(sh) (sh)->stroke_width
 
 
 /*! \brief A sprite is a set of graphics that being an object in animation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/Makefile.am	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,24 @@
+
+mbfly_node_SRCS = mbfly_njs.cc X_supp_njs.c coord.cc shapes.cc paints.cc
+mbfly_node_CFLAGS= -I$(abs_top_builddir)/include \
+	-I$(abs_top_srcdir)/include \
+	-I$(prefix)/include \
+	@pangocairo_CFLAGS@ $(CFLAGS)
+mbfly_node_LDFLAGS = -L$(abs_top_builddir)/src/.libs @pangocairo_LIBS@
+
+all: mbfly.node
+clean: clean-mbfly-node
+
+mbfly.node: wscript $(mbfly_node_SRCS)
+	cd $(srcdir); \
+	CFLAGS="$(mbfly_node_CFLAGS)" \
+		CXXFLAGS="$(mbfly_node_CFLAGS)" \
+		LDFLAGS="$(mbfly_node_LDFLAGS)" \
+		TOP_BUILDDIR="$(abs_top_builddir)" \
+		WAFLOCK=$(abs_builddir)/.lock-wscript \
+		$(NODE_WAF) configure build --blddir=$(abs_builddir)
+
+clean-mbfly-node:
+	cd $(srcdir); \
+	WAFLOCK=$(abs_builddir)/.lock-wscript \
+		$(NODE_WAF) clean
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/X_supp_njs.c	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,151 @@
+/*! \brief Implement X11 backend for nodejs plugin.
+ *
+ * Since nodejs use libev to handle event loops, part of X11 backend
+ * code can not be used directly.  The part of code should be rewrote.
+ * The part is about
+ */
+#include <stdio.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <ev.h>
+#include "mb_X_supp.h"
+#include "mb_tools.h"
+#include "X_supp_njs.h"
+
+#ifndef ASSERT
+#define ASSERT(x)
+#endif
+
+static void timer_cb(EV_P_ ev_timer *tmwatcher, int revent);
+
+/*! \brief Register next timeout with libev.
+ */
+static void
+set_next_timeout(njs_runtime_t *rt) {
+    mb_tman_t *tman;
+    mb_timeval_t now, tmo;
+    ev_tstamp tout;
+    int r;
+    
+    tman = X_MB_tman(rt->xrt);
+    get_now(&now);
+    r = mb_tman_next_timeout(tman, &now, &tmo);
+    if(r == 0) {
+	MB_TIMEVAL_DIFF(&tmo, &now);
+	tout = (ev_tstamp)MB_TIMEVAL_SEC(&tmo) +
+	    (ev_tstamp)MB_TIMEVAL_USEC(&tmo) / 1000000;
+	ev_timer_init(&rt->tmwatcher, timer_cb, tout, 0);
+	ev_timer_start(&rt->tmwatcher);
+	rt->enable_timer = 1;
+    } else
+	rt->enable_timer = 0;
+}
+
+static void
+x_conn_cb(EV_P_ ev_io *iowatcher, int revent) {
+    njs_runtime_t *rt = MEM2OBJ(iowatcher, njs_runtime_t, iowatcher);
+    redraw_man_t *rdman;
+    extern void _X_MB_handle_x_event_for_nodejs(void *rt);
+
+    rdman = X_MB_rdman(rt->xrt);
+    _X_MB_handle_x_event_for_nodejs(rt->xrt);
+    rdman_redraw_changed(rdman);
+    
+    if(rt->enable_timer == 0) /* no installed timeout */
+	set_next_timeout(rt);
+}
+
+static void
+timer_cb(EV_P_ ev_timer *tmwatcher, int revent) {
+    njs_runtime_t *rt = MEM2OBJ(tmwatcher, njs_runtime_t, tmwatcher);
+    mb_tman_t *tman;
+    redraw_man_t *rdman;
+    mb_timeval_t now;
+    extern int _X_MB_flush_x_conn_for_nodejs(void *rt);
+    
+    tman = X_MB_tman(rt->xrt);
+    get_now(&now);
+    mb_tman_handle_timeout(tman, &now);
+
+    rdman = X_MB_rdman(rt->xrt);
+    rdman_redraw_changed(rdman);
+    _X_MB_flush_x_conn_for_nodejs(rt->xrt);
+    
+    set_next_timeout(rt);
+}
+
+/*! \brief Handle connection coming data and timeout of timers.
+ *
+ * \param rt is a runtime object for X.
+ */
+void
+X_njs_MB_init_handle_connection(njs_runtime_t *rt) {
+    void *xrt = rt->xrt;
+    mb_tman_t *tman;
+    mb_timeval_t now, tmo;
+    ev_tstamp tout;
+    int fd;
+    int r;
+    extern int _X_MB_get_x_conn_for_nodejs(void *rt);
+
+    /*
+     * Setup watcher for X connection.
+     */
+    fd = _X_MB_get_x_conn_for_nodejs(xrt);
+    ev_io_init(&rt->iowatcher, x_conn_cb, fd, EV_READ);
+    ev_io_start(&rt->iowatcher);
+    rt->enable_io = 1;
+
+    set_next_timeout(rt);
+}
+
+/*! \brief Free njs_runtime_t.
+ */
+void
+X_njs_MB_free(njs_runtime_t *rt) {
+    /*
+     * stop IO and timer watcher
+     */
+    if(rt->enable_io)
+	ev_io_stop(&rt->iowatcher);
+    if(rt->enable_timer)
+	ev_timer_stop(&rt->tmwatcher);
+    
+    X_MB_free(rt->xrt);
+    free(rt);
+}
+
+int
+X_njs_MB_flush(njs_runtime_t *rt) {
+    void *xrt = rt->xrt;
+    int r;
+    extern int _X_MB_flush_x_conn_for_nodejs(void *rt);
+
+    _X_MB_flush_x_conn_for_nodejs(xrt);
+    
+    return r;
+}
+
+njs_runtime_t *
+X_njs_MB_new(char *display_name, int w, int h) {
+    njs_runtime_t *rt;
+    void *xrt;
+    
+    rt = (njs_runtime_t *)malloc(sizeof(njs_runtime_t));
+    ASSERT(rt != NULL);
+
+    xrt = X_MB_new(display_name, w, h);
+
+    rt->xrt = xrt;
+    rt->enable_io = 0;
+    rt->enable_timer = 0;	/* no timer, now */
+    
+    return rt;
+}
+
+/*! \brief Get X runtime that is backend of this njs runtime.
+ */
+void *
+_X_njs_MB_get_X_runtime(njs_runtime_t *rt) {
+    return rt->xrt;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/X_supp_njs.h	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,26 @@
+#ifndef __X_SUPP_NJS_H_
+#define __X_SUPP_NJS_H_
+
+#include <ev.h>
+
+typedef struct _njs_runtime {
+    ev_io iowatcher;
+    ev_timer tmwatcher;
+    int enable_io;
+    int enable_timer;
+    void *xrt;
+} njs_runtime_t;
+
+extern void X_njs_MB_init_handle_connection(njs_runtime_t *rt);
+extern void X_njs_MB_free(njs_runtime_t *rt);
+extern njs_runtime_t *X_njs_MB_new(char *display_name, int w, int h);
+extern int X_njs_MB_flush(njs_runtime_t *rt);
+extern void *_X_njs_MB_get_X_runtime(njs_runtime_t *rt);
+
+#define X_njs_MB_kbevents(rt) X_MB_kbevents((rt)->xrt)
+#define X_njs_MB_rdman(rt) X_MB_rdman((rt)->xrt)
+#define X_njs_MB_tman(rt) X_MB_tman((rt)->xrt)
+#define X_njs_MB_ob_factory(rt) X_MB_ob_factory((rt)->xrt)
+#define X_njs_MB_img_ldr(rt) X_MB_img_ldr((rt)->xrt)
+
+#endif /* __X_SUPP_NJS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/coord.cc	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,194 @@
+#include <stdio.h>
+#include <v8.h>
+
+extern "C" {
+#include "mb.h"
+#include "mb_X_supp.h"
+#include "mb_tools.h"
+#include "X_supp_njs.h"
+}
+
+#include "mbfly_njs.h"
+
+#ifndef ASSERT
+#define ASSERT(x)
+#endif
+
+using namespace v8;
+
+static Handle<Value>
+xnjsmb_coord_get_index(uint32_t index, const AccessorInfo &info) {
+    HandleScope scope;
+    Handle<Object> self;
+    coord_t *coord;
+    co_aix v;
+
+    if(index < 0 || index >= 6)
+	THROW("Invalid index");
+    
+    self = info.This();
+    coord = (coord_t *)UNWRAP(self);
+    v = coord_get_matrix(coord)[index];
+
+    return Number::New(v);
+}
+
+static Handle<Value>
+xnjsmb_coord_set_index(uint32_t index, Local<Value> value,
+		       const AccessorInfo &info) {
+    
+    HandleScope scope;
+    Handle<Object> self;
+    Handle<Object> js_rt;
+    redraw_man_t *rdman;
+    coord_t *coord;
+    co_aix v;
+
+    if(index < 0 || index >= 6)
+	THROW("Invalid Index");
+    if(!value->IsNumber())
+	THROW("Invalid value");
+
+    self = info.This();
+    coord = (coord_t *)UNWRAP(self);
+    v = value->NumberValue();
+    coord_get_matrix(coord)[index] = v;
+
+    js_rt = GET(self, "mbrt")->ToObject();
+    rdman = xnjsmb_rt_rdman(js_rt);
+    rdman_coord_changed(rdman, coord);
+
+    return value;
+}
+
+/*! \brief Callback functio to add a shape to a coord in Javascript.
+ *
+ * coord.add_shape(shape)
+ */
+static Handle<Value>
+xnjsmb_coord_add_shape(const Arguments &args) {
+    int argc = args.Length();
+    Handle<Object> self = args.This();
+    Handle<Object> shape_obj;
+    Handle<Object> rt_obj;
+    Handle<Value> rt_val;
+    redraw_man_t *rdman;
+    coord_t *coord;
+    shape_t *sh;
+    int r;
+
+    if(argc != 1)
+	THROW("Invalid number of arguments (!= 1)");
+    
+    shape_obj = args[0]->ToObject();
+    sh = (shape_t *)UNWRAP(shape_obj);
+    ASSERT(sh != NULL);
+    
+    coord = (coord_t *)UNWRAP(self);
+    ASSERT(coord != NULL);
+
+    rt_val = GET(self, "mbrt");
+    rt_obj = rt_val->ToObject();
+    rdman = xnjsmb_rt_rdman(rt_obj);
+    
+    r = rdman_add_shape(rdman, sh, coord);
+    if(r != 0)
+	THROW("Unknown error");
+
+    return Null();
+}
+
+static Persistent<ObjectTemplate> coord_obj_temp;
+
+static void
+xnjsmb_init_temp(void) {
+    Handle<FunctionTemplate> add_shape_temp;
+    
+    coord_obj_temp = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
+    coord_obj_temp->SetIndexedPropertyHandler(xnjsmb_coord_get_index,
+					      xnjsmb_coord_set_index);
+    coord_obj_temp->SetInternalFieldCount(1);
+
+    add_shape_temp = FunctionTemplate::New(xnjsmb_coord_add_shape);
+    SET(coord_obj_temp, "add_shape", add_shape_temp);
+}
+
+/*! \brief Create and initialize a Javascript object for a coord.
+ */
+static Handle<Object>
+xnjsmb_coord_new_jsobj(coord_t *coord, Handle<Object> parent_obj,
+		       Handle<Object> js_rt) {
+    Handle<Object> coord_obj;
+    static int init_temp = 0;
+    
+    if(!init_temp) {
+	xnjsmb_init_temp();
+	init_temp = 1;
+    }
+
+    coord_obj = coord_obj_temp->NewInstance();
+    ASSERT(coord_obj != NULL);
+    WRAP(coord_obj, coord);
+
+    if(!parent_obj.IsEmpty())
+	SET(coord_obj, "parent", parent_obj);
+    SET(coord_obj, "mbrt", js_rt);
+
+    return coord_obj;
+}
+
+/*! \brief Create a coord object associated with the rdman of the runtime.
+ *
+ * Two internal fields, coord and rdman.
+ */
+Handle<Value>
+xnjsmb_coord_new(const Arguments &args) {
+    HandleScope scope;
+    Handle<Object> js_rt;
+    Handle<Object> coord_obj, parent_obj;
+    njs_runtime_t *rt;
+    redraw_man_t *rdman;
+    coord_t *coord, *parent = NULL;
+    int argc;
+
+    argc = args.Length();
+    if(argc > 1)
+	THROW("Too many arguments (> 1)");
+
+    js_rt = args.This();
+    rt = (njs_runtime_t *)UNWRAP(js_rt);
+    rdman = X_njs_MB_rdman(rt);
+
+    if(argc == 1) {
+	parent_obj = args[0]->ToObject();
+	parent = (coord_t *)UNWRAP(parent_obj);
+    }
+    
+    coord = rdman_coord_new(rdman, parent);
+    ASSERT(coord != NULL);
+    coord_obj = xnjsmb_coord_new_jsobj(coord, parent_obj, js_rt);
+
+    scope.Close(coord_obj);
+    
+    return coord_obj;
+}
+
+/*! \brief Initialize Javascript object for root coord of a runtime.
+ *
+ * \param js_rt is the runtime object to create the root object for.
+ *
+ * After the function, js_rt.root is the object for root coord in
+ * Javascript.
+ */
+void
+xnjsmb_coord_mkroot(Handle<Object> js_rt) {
+    redraw_man_t *rdman;
+    coord_t *root;
+    Handle<Object> obj;
+    
+    rdman = xnjsmb_rt_rdman(js_rt);
+    root = rdman_get_root(rdman);
+    obj = xnjsmb_coord_new_jsobj(root, Handle<Object>(NULL), js_rt);
+
+    SET(js_rt, "root", obj);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/mbfly_njs.cc	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,152 @@
+#include <stdio.h>
+#include <v8.h>
+
+extern "C" {
+#include "X_supp_njs.h"
+}
+
+#include "mbfly_njs.h"
+
+using namespace v8;
+
+/*! \defgroup njs_template_cb Callback functions for v8 engine and nodejs.
+ *
+ * @{
+ */
+
+/*! \brief to Create a njs runtime object for MadButterfly.
+ *
+ * Three arguments are requried.  They are
+ *   - display name,
+ *   - width, and
+ *   - height.
+ */
+static Handle<Value>
+xnjsmb_new(const Arguments &args) {
+    HandleScope scope;
+    int argc;
+    Handle<Value> exc;
+    njs_runtime_t *rt;
+    char *display_name;
+    int width, height;
+    Handle<Object> self;
+
+    argc = args.Length();
+    if(argc != 3) {
+	exc = Exception::Error(String::New("Need 3 arguments."));
+	return ThrowException(exc);
+    }
+
+    if(!args[0]->IsString() || !args[1]->IsInt32() || !args[2]->IsInt32()) {
+	exc = Exception::Error(String::New("Invalid argument type."));
+	return ThrowException(exc);
+    }
+    
+    String::Utf8Value disp_utf8(args[0]->ToString());
+    display_name = *disp_utf8;
+    width = args[1]->Int32Value();
+    height = args[2]->Int32Value();
+    rt = X_njs_MB_new(display_name, width, height);
+
+    self = args.This();
+    WRAP(self, rt);
+    xnjsmb_coord_mkroot(self);
+    
+    X_njs_MB_init_handle_connection(rt);
+
+    return Null();
+}
+
+static Handle<Value>
+xnjsmb_handle_connection(const Arguments &args) {
+}
+
+static Handle<Value>
+xnjsmb_rt_redraw_changed(const Arguments &args) {
+    Handle<Object> self = args.This();
+    njs_runtime_t *rt;
+    redraw_man_t *rdman;
+    
+    rdman = xnjsmb_rt_rdman(self);
+    rdman_redraw_changed(rdman);
+    
+    rt = (njs_runtime_t *)UNWRAP(self);
+    X_njs_MB_flush(rt);
+    
+    return Null();
+}
+
+static Handle<Value>
+xnjsmb_rt_redraw_all(const Arguments &args) {
+    Handle<Object> self = args.This();
+    njs_runtime_t *rt;
+    redraw_man_t *rdman;
+    
+    rdman = xnjsmb_rt_rdman(self);
+    rdman_redraw_all(rdman);
+    
+    rt = (njs_runtime_t *)UNWRAP(self);
+    X_njs_MB_flush(rt);
+    
+    return Null();
+}
+
+/* @} */
+
+/*! \brief Get rdman associated with the runtime.
+ */
+redraw_man_t *
+xnjsmb_rt_rdman(Handle<Object> mbrt) {
+    HandleScope scope;
+    njs_runtime_t *rt;
+    redraw_man_t *rdman;
+
+    rt = (njs_runtime_t *)UNWRAP(mbrt);
+    rdman = X_njs_MB_rdman(rt);
+    
+    return rdman;
+}
+
+Handle<Value>
+hello_func(const Arguments &args) {
+    HandleScope scope;
+
+    return String::Concat(String::New("World"), args[0]->ToString());
+}
+
+extern "C" void
+init(Handle<Object> target) {
+    HandleScope scope;
+    Handle<FunctionTemplate> func, mb_rt_func;
+    Handle<ObjectTemplate> rt_instance_temp, rt_proto_temp;
+
+    func = FunctionTemplate::New(hello_func);
+    target->Set(String::New("Hello"), func->GetFunction());
+
+    /*
+     * Initialize template for MadButterfly runtime objects.
+     */
+    mb_rt_func = FunctionTemplate::New(xnjsmb_new);
+    mb_rt_func->SetClassName(String::New("mb_rt"));
+    
+    rt_instance_temp = mb_rt_func->InstanceTemplate();
+    rt_instance_temp->SetInternalFieldCount(1);
+    
+    rt_proto_temp = mb_rt_func->PrototypeTemplate();
+    func = FunctionTemplate::New(xnjsmb_coord_new);
+    SET(rt_proto_temp, "coord_new", func);
+
+    func = FunctionTemplate::New(xnjsmb_rt_redraw_changed);
+    SET(rt_proto_temp, "redraw_changed", func);
+
+    func = FunctionTemplate::New(xnjsmb_rt_redraw_all);
+    SET(rt_proto_temp, "redraw_all", func);
+
+    /*
+     * Add properties to mb_rt templates for other modules.
+     */
+    xnjsmb_shapes_init_mb_rt_temp(mb_rt_func);
+    xnjsmb_paints_init_mb_rt_temp(mb_rt_func);
+    
+    target->Set(String::New("mb_rt"), mb_rt_func->GetFunction());    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/mbfly_njs.h	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,32 @@
+#ifndef __MBFLY_NJS_H_
+#define __MBFLY_NJS_H_
+
+#include <v8.h>
+extern "C" {
+#include <mb.h>
+}
+
+#define THROW(x)						\
+    do {							\
+	v8::Handle<v8::Value> exc;				\
+	exc = v8::Exception::Error(v8::String::New(x));		\
+	return v8::ThrowException(exc);				\
+    } while(0)
+#define UNWRAP(o) v8::External::Unwrap((o)->GetInternalField(0))
+#define WRAP(o, v) (o)->SetInternalField(0, v8::External::Wrap(v))
+#define SET(o, n, v) (o)->Set(v8::String::New(n), v)
+#define GET(o, n) (o)->Get(v8::String::New(n))
+
+redraw_man_t *xnjsmb_rt_rdman(v8::Handle<v8::Object> mbrt);
+
+/* From coord.cc */
+v8::Handle<v8::Value> xnjsmb_coord_new(const v8::Arguments &args);
+void xnjsmb_coord_mkroot(v8::Handle<v8::Object> js_rt);
+
+/* From shapes.cc */
+void xnjsmb_shapes_init_mb_rt_temp(v8::Handle<v8::FunctionTemplate> rt_temp);
+
+/* From paints.cc */
+void xnjsmb_paints_init_mb_rt_temp(v8::Handle<v8::FunctionTemplate> rt_temp);
+
+#endif /* __MBFLY_NJS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/paints.cc	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,206 @@
+#include <v8.h>
+
+extern "C" {
+#include "mb.h"
+}
+
+#include "mbfly_njs.h"
+
+using namespace v8;
+
+#ifndef ASSERT
+#define ASSERT(x)
+#endif
+
+
+/*! \brief Fill a shape with the paint.
+ */
+static Handle<Value>
+xnjsmb_paint_fill(const Arguments &args) {
+    int argc = args.Length();
+    Handle<Object> self = args.This();
+    Handle<Object> sh_obj;
+    Handle<Object> rt;
+    Handle<Value> rt_val;
+    paint_t *paint;
+    shape_t *sh;
+    redraw_man_t *rdman;
+
+    if(argc != 1)
+	THROW("Invalid number of arguments (!= 1)");
+    if(!args[0]->IsObject())
+	THROW("Invalid argument type (shape)");
+
+    paint = (paint_t *)UNWRAP(self);
+    
+    sh_obj = args[0]->ToObject();
+    sh = (shape_t *)UNWRAP(sh_obj);
+
+    rt_val = GET(self, "mbrt");
+    rt = rt_val->ToObject();
+    rdman = xnjsmb_rt_rdman(rt);
+    
+    rdman_paint_fill(rdman, paint, sh);
+    
+    rdman_shape_changed(rdman, sh);
+    
+    return Null();
+}
+
+/*! \brief Stroke a shape with the paint.
+ */
+static Handle<Value>
+xnjsmb_paint_stroke(const Arguments &args) {
+    int argc = args.Length();
+    Handle<Object> self = args.This();
+    Handle<Object> sh_obj;
+    Handle<Object> rt;
+    Handle<Value> rt_val, sh_val;
+    paint_t *paint;
+    shape_t *sh;
+    redraw_man_t *rdman;
+
+    if(argc != 1)
+	THROW("Invalid number of arguments (!= 1)");
+    if(!args[0]->IsObject())
+	THROW("Invalid argument type (shape)");
+
+    paint = (paint_t *)UNWRAP(self);
+    
+    sh_val = args[0];
+    sh_obj = sh_val->ToObject();
+    sh = (shape_t *)UNWRAP(sh_obj);
+
+    rt_val = GET(self, "mbrt");
+    rt = rt_val->ToObject();
+    rdman = xnjsmb_rt_rdman(rt);
+    
+    rdman_paint_stroke(rdman, paint, sh);
+    
+    rdman_shape_changed(rdman, sh);
+    
+    return Null();
+}
+
+/*! \brief Constructor of color paint_color_t object for Javascript.
+ */
+static Handle<Value>
+xnjsmb_paint_color(const Arguments &args) {
+    int argc = args.Length();
+    Handle<Object> self = args.This();
+    Handle<Object> rt;
+    redraw_man_t *rdman;
+    paint_t *paint;
+    float r, g, b, a;
+
+    if(argc != 5)
+	THROW("Invalid number of arguments (!= 5)");
+    if(!args[0]->IsObject() || !args[1]->IsNumber() ||
+       !args[2]->IsNumber() || !args[3]->IsNumber() ||
+       !args[4]->IsNumber())
+	THROW("Invalid argument type");
+
+    rt = args[0]->ToObject();
+    r = args[1]->ToNumber()->Value();
+    g = args[2]->ToNumber()->Value();
+    b = args[3]->ToNumber()->Value();
+    a = args[4]->ToNumber()->Value();
+
+    rdman = xnjsmb_rt_rdman(rt);
+    paint = rdman_paint_color_new(rdman, r, g, b, a);
+    ASSERT(sh != NULL);
+
+    WRAP(self, paint);
+    SET(self, "mbrt", rt);
+
+    return Null();
+}
+
+static Persistent<FunctionTemplate> xnjsmb_paint_temp;
+static Persistent<FunctionTemplate> xnjsmb_paint_color_temp;
+
+/*! \brief Create and return a paint_color object.
+ */
+static Handle<Value>
+xnjsmb_paint_color_new(const Arguments &args) {
+    HandleScope scope;
+    Handle<Object> rt = args.This();
+    Handle<Object> paint_color_obj;
+    Handle<Function> paint_color_func;
+    Handle<Value> pc_args[5];
+    int argc;
+    int i;
+
+    argc = args.Length();
+    if(argc != 4)
+	THROW("Invalid number of arguments (r, g, b, a)");
+    for(i = 0; i < 4; i++)
+	if(!args[i]->IsNumber())
+	    THROW("Invalid argument type");
+    
+    pc_args[0] = rt;
+    pc_args[1] = args[0];	// r
+    pc_args[2] = args[1];	// g
+    pc_args[3] = args[2];	// b
+    pc_args[4] = args[3];	// a
+    paint_color_func = xnjsmb_paint_color_temp->GetFunction();
+    paint_color_obj = paint_color_func->NewInstance(5, pc_args);
+
+    scope.Close(paint_color_obj);
+    return paint_color_obj;
+}
+
+static Persistent<FunctionTemplate> xnjsmb_paint_color_new_temp;
+
+/*! \brief Create templates for paint types.
+ *
+ * This function is only called one time for every execution.
+ */
+static void
+xnjsmb_init_paints(void) {
+    Handle<FunctionTemplate> temp, meth;
+    Handle<ObjectTemplate> inst_temp;
+    Handle<ObjectTemplate> proto_temp;
+    
+    /*
+     * Base type of paint types.
+     */
+    temp = FunctionTemplate::New();
+    xnjsmb_paint_temp = Persistent<FunctionTemplate>::New(temp);
+    xnjsmb_paint_temp->SetClassName(String::New("paint"));
+    
+    meth = FunctionTemplate::New(xnjsmb_paint_fill);
+    proto_temp = xnjsmb_paint_temp->PrototypeTemplate();
+    SET(proto_temp, "fill", meth);
+
+    meth = FunctionTemplate::New(xnjsmb_paint_stroke);
+    proto_temp = xnjsmb_paint_temp->PrototypeTemplate();
+    SET(proto_temp, "stroke", meth);
+
+    /*
+     * Paint color
+     */
+    temp = FunctionTemplate::New(xnjsmb_paint_color);
+    xnjsmb_paint_color_temp = Persistent<FunctionTemplate>::New(temp);
+    xnjsmb_paint_color_temp->SetClassName(String::New("paint_color"));
+    xnjsmb_paint_color_temp->Inherit(xnjsmb_paint_temp);
+    
+    inst_temp = xnjsmb_paint_color_temp->InstanceTemplate();
+    inst_temp->SetInternalFieldCount(1);
+
+    temp = FunctionTemplate::New(xnjsmb_paint_color_new);
+    xnjsmb_paint_color_new_temp = Persistent<FunctionTemplate>::New(temp);
+}
+
+void xnjsmb_paints_init_mb_rt_temp(Handle<FunctionTemplate> rt_temp) {
+    static int init_flag = 0;
+    Handle<ObjectTemplate> rt_proto_temp;
+
+    if(!init_flag) {
+	xnjsmb_init_paints();
+	init_flag = 1;
+    }
+
+    rt_proto_temp = rt_temp->PrototypeTemplate();
+    SET(rt_proto_temp, "paint_color_new", xnjsmb_paint_color_new_temp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/shapes.cc	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,213 @@
+#include <v8.h>
+#include "mbfly_njs.h"
+
+extern "C" {
+#include <mb.h>
+}
+
+#ifndef ASSERT
+#define ASSERT(x)
+#endif
+
+using namespace v8;
+
+/*! \defgroup shape_temp Templates for shape and derivations.
+ *
+ * @{
+ */
+static Persistent<FunctionTemplate> xnjsmb_shape_temp;
+
+static Handle<Value>
+xnjsmb_shape_show(const Arguments &args) {
+    shape_t *sh;
+    Handle<Object> self;
+
+    self = args.This();
+    sh = (shape_t *)UNWRAP(self);
+    sh_show(sh);
+    
+    return Null();
+}
+
+static Handle<Value>
+xnjsmb_shape_hide(const Arguments &args) {
+    shape_t *sh;
+    Handle<Object> self;
+
+    self = args.This();
+    sh = (shape_t *)UNWRAP(self);
+    sh_hide(sh);
+    
+    return Null();
+}
+
+/*! \brief Get stroke width of a shape.
+ */
+static Handle<Value>
+xnjsmb_shape_stroke_width_getter(Local<String> property,
+				 const AccessorInfo &info) {
+    Handle<Object> self = info.This();
+    shape_t *sh;
+    float w;
+    Handle<Value> w_val;
+    
+    sh = (shape_t *)UNWRAP(self);
+    w = sh_get_stroke_width(sh);
+    w_val = Number::New(w);
+    
+    return w_val;
+}
+
+/*! \brief Set stroke width of a shape.
+ */
+static void
+xnjsmb_shape_stroke_width_setter(Local<String> property,
+				 Local<Value> value,
+				 const AccessorInfo &info) {
+    Handle<Object> self = info.This();
+    Handle<Object> rt;
+    shape_t *sh;
+    redraw_man_t *rdman;
+    float w;
+    Handle<Number> w_num;
+    
+    sh = (shape_t *)UNWRAP(self);
+    w_num = value->ToNumber();
+    w = w_num->Value();
+
+    sh_set_stroke_width(sh, w);
+
+    /*
+     * Mark changed.
+     */
+    rt = GET(self, "mbrt")->ToObject();
+    ASSERT(rt != NULL);
+    rdman = xnjsmb_rt_rdman(rt);
+    
+    rdman_shape_changed(rdman, sh);
+}
+
+static void
+xnjsmb_init_shape_temp(void) {
+    Handle<FunctionTemplate> temp;
+    Handle<ObjectTemplate> proto_temp;
+    Handle<FunctionTemplate> method_temp;
+
+    temp = FunctionTemplate::New();
+    temp->SetClassName(String::New("shape"));
+    xnjsmb_shape_temp = Persistent<FunctionTemplate>::New(temp);
+    proto_temp = temp->PrototypeTemplate();
+    
+    method_temp = FunctionTemplate::New(xnjsmb_shape_show);
+    SET(proto_temp, "show", method_temp);
+    method_temp = FunctionTemplate::New(xnjsmb_shape_hide);
+    SET(proto_temp, "hide", method_temp);
+
+    proto_temp->SetAccessor(String::New("stroke_width"),
+			    xnjsmb_shape_stroke_width_getter,
+			    xnjsmb_shape_stroke_width_setter);
+}
+
+/* @} */
+
+/*! \defgroup path_temp Templates for path objects.
+ *
+ * @{
+ */
+static Persistent<FunctionTemplate> xnjsmb_path_temp;
+
+/*! \brief Callback of constructor of path objects for Javascript.
+ */
+static Handle<Value>
+xnjsmb_shape_path(const Arguments &args) {
+    shape_t *sh;
+    redraw_man_t *rdman;
+    Handle<Object> self = args.This(); // path object
+    Handle<Object> rt;
+    char *dstr;
+    int argc;
+
+    argc = args.Length();
+    if(argc != 2)
+	THROW("Invalid number of arugments (!= 1)");
+    if(!args[0]->IsString())
+	THROW("Invalid argument type (should be a string)");
+    if(!args[1]->IsObject())
+	THROW("Invalid argument type (should be an object)");
+
+    String::Utf8Value dutf8(args[0]->ToString());
+    dstr = *dutf8;
+
+    rt = args[1]->ToObject();
+    rdman = xnjsmb_rt_rdman(rt);
+    sh = rdman_shape_path_new(rdman, dstr);
+
+    WRAP(self, sh);
+    SET(self, "mbrt", rt);
+
+    return Null();
+}
+
+/*! \brief Initial function template for constructor of path objects.
+ */
+static void
+xnjsmb_init_path_temp(void) {
+    Handle<FunctionTemplate> temp;
+    Handle<ObjectTemplate> inst_temp;
+
+    temp = FunctionTemplate::New(xnjsmb_shape_path);
+    temp->Inherit(xnjsmb_shape_temp);
+    temp->SetClassName(String::New("path"));
+
+    inst_temp = temp->InstanceTemplate();
+    inst_temp->SetInternalFieldCount(1);
+
+    xnjsmb_path_temp = Persistent<FunctionTemplate>::New(temp);
+}
+
+/*! \brief Callback function of mb_rt.path_new().
+ */
+static Handle<Value>
+xnjsmb_shape_path_new(const Arguments &args) {
+    HandleScope scope;
+    Handle<Object> self = args.This(); // runtime object
+    Handle<Object> path_obj;
+    Handle<Value> path_args[2];
+    int argc;
+
+    argc = args.Length();
+    if(argc != 1)
+	THROW("Invalid number of arugments (!= 1)");
+    if(!args[0]->IsString())
+	THROW("Invalid argument type (shoud be a string)");
+
+    path_args[0] = args[0];
+    path_args[1] = self;
+    
+    path_obj = xnjsmb_path_temp->GetFunction()->NewInstance(2, path_args);
+    
+    scope.Close(path_obj);
+    return path_obj;
+}
+
+/* @} */
+
+/*! \brief Set properties of template of mb_rt.
+ */
+void
+xnjsmb_shapes_init_mb_rt_temp(Handle<FunctionTemplate> rt_temp) {
+    Handle<FunctionTemplate> path_new_temp;
+    Handle<ObjectTemplate> rt_proto_temp;
+    static int temp_init_flag = 0;
+
+    if(temp_init_flag == 0) {
+	xnjsmb_init_shape_temp();
+	xnjsmb_init_path_temp();
+	temp_init_flag = 1;
+    }
+
+    rt_proto_temp = rt_temp->PrototypeTemplate();
+    
+    path_new_temp = FunctionTemplate::New(xnjsmb_shape_path_new);
+    SET(rt_proto_temp, "path_new", path_new_temp);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/testcase.js	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,37 @@
+var mbfly = require("mbfly");
+var r = mbfly.Hello(" test");
+var sys = require("sys");
+sys.puts(r);
+
+var mb_rt = new mbfly.mb_rt(":0.0", 300, 200);
+var root = mb_rt.root;
+sys.puts("root matrix: " +
+	 [root[0], root[1], root[2], root[3], root[4], root[5]]);
+var coord = mb_rt.coord_new(root);
+sys.puts("coord matrix: " + 
+	 [coord[0], coord[1], coord[2], coord[3], coord[4], coord[5]]);
+
+sys.puts(mb_rt.path_new);
+var path = mb_rt.path_new("m 100,50 L 120,50 L 200,150 L 180,150 z");
+sys.puts(path);
+sys.puts(coord.add_shape);
+coord.add_shape(path);
+
+sys.puts(mb_rt.paint_color_new);
+var paint = mb_rt.paint_color_new(1.0, 1.0, 1.0, 1.0);
+sys.puts(paint);
+paint.stroke(path);
+
+sys.puts(path.stroke_width);
+path.stroke_width = 2;
+sys.puts(path.stroke_width);
+
+mb_rt.redraw_all();
+
+var i = 0;
+setInterval(function() {
+	var deg = (i++) * 0.1;
+	coord[2] = (i % 20) * 10;
+	mb_rt.redraw_changed();
+    }, 50);
+setTimeout(function() { sys.puts("timeout"); }, 1000);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nodejs/wscript	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,33 @@
+srcdir = '.'
+blddir = 'build'
+VERSION = '0.0.1'
+
+def set_options(opt):
+    opt.tool_options('compiler_cxx')
+    opt.tool_options('compiler_cc')
+    pass
+
+def configure(conf):
+    import Options
+    import os
+    
+    conf.check_tool('compiler_cxx')
+    conf.check_tool('compiler_cc')
+    conf.check_tool('node_addon')
+    conf.env.SRCDIR = Options.options.srcdir
+    conf.env.TOP_BUILDDIR = os.environ['TOP_BUILDDIR']    
+    pass
+
+def build(conf):
+    import Utils
+    
+    obj = conf.new_task_gen('cxx', 'shlib', 'node_addon')
+    obj.target = 'mbfly'
+    obj.source = 'mbfly_njs.cc coord.cc shapes.cc paints.cc'
+    obj.add_objects = 'X_supp_njs.o'
+    obj.staticlib = 'mbfly'
+    
+    obj = conf.new_task_gen('cc', 'shlib', 'node_addon')
+    obj.target = 'X_supp_njs.o'
+    obj.source = 'X_supp_njs.c'
+    pass
--- a/src/Makefile.am	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/Makefile.am	Wed Jun 09 17:30:09 2010 +0800
@@ -12,11 +12,16 @@
 noinst_PROGRAMS += testcase
 endif
 
+if X_SUPP
 MBAF_SOURCES=mbaf/mbapp.c mbaf/mbbutton.c mbaf/mbobject.c mbaf/animated_menu.c
+else
+MBAF_SOURCES=
+endif
+
 libmbfly_la_SOURCES= animate.c chgcolor.c coord.c event.c geo.c	\
 	observer.c paint.c redraw_man.c rotate.c shape_path.c		\
 	shape_rect.c shift.c subtree_free.c timer.c 			\
-	timertool.c tools.c visibility.c X_supp.c prop.c sprite.c	\
+	timertool.c tools.c visibility.c prop.c sprite.c	\
 	mouse.c shape_image.c img_ldr.c $(MBAF_SOURCES)
 
 if SH_TEXT
@@ -27,8 +32,20 @@
 libmbfly_la_SOURCES += shape_stext.c
 endif
 
+if X_SUPP
+libmbfly_la_SOURCES += X_supp.c
+endif
+
+if CAIRO_GRAPH_ENGINE
+libmbfly_la_SOURCES += graph_engine_cairo.c
+
 libmbfly_la_CPPFLAGS = @cairo_CFLAGS@ @pangocairo_CFLAGS@
 libmbfly_la_LDFLAGS = @cairo_LIBS@ @pangocairo_LIBS@
+endif
+
+if SKIA_GRAPH_ENGINE
+libmbfly_la_SOURCES += graph_engine_skia.cpp
+endif
 
 X_main_SOURCES = X_main.c
 X_main_LDADD = $(top_builddir)/src/libmbfly.la
--- a/src/X_main.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/X_main.c	Wed Jun 09 17:30:09 2010 +0800
@@ -122,6 +122,7 @@
 void draw_path(mbe_t *cr, int w, int h) {
     mbe_t *tmpcr;
     mbe_surface_t *tmpsuf;
+    mbe_pattern_t *tmpptn;
     redraw_man_t rdman;
     shape_t *path1, *path2, *rect;
     coord_t *coord1, *coord2, *coord3;
@@ -141,9 +142,10 @@
     PangoAttrList *attrs = pango_attr_list_new();
 
     tmpsuf = mbe_image_surface_create(MB_IFMT_ARGB32, w, h);
+    tmpptn = mbe_pattern_create_for_surface(tmpsuf);
     tmpcr = mbe_create(tmpsuf);
 
-    mbe_set_source_surface(cr, tmpsuf, 0, 0);
+    mbe_set_source(cr, tmpptn);
     redraw_man_init(&rdman, tmpcr, cr);
     coord1 = rdman_coord_new(&rdman, rdman.root_coord);
     coord2 = rdman_coord_new(&rdman, rdman.root_coord);
--- a/src/X_supp.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/X_supp.c	Wed Jun 09 17:30:09 2010 +0800
@@ -37,6 +37,7 @@
     Window win;
     Visual *visual;
     mbe_surface_t *surface, *backend_surface;
+    mbe_pattern_t *surface_ptn;
     mbe_t *cr, *backend_cr;
     redraw_man_t *rdman;
     mb_tman_t *tman;
@@ -201,6 +202,10 @@
     int in_stroke;
     int r;
 
+    /* XXX: For some unknown reason, it causes a segmentation fault to
+     *      called XEventsQueued() after receiving first Expose event
+     *      and before redraw for the event.
+     */
     while(XEventsQueued(display, QueuedAfterReading) > 0) {
 	r = XNextEvent(display, &evt);
 	if(r == -1)
@@ -466,6 +471,9 @@
 
     xmb_rt->surface =
 	mbe_image_surface_create(MB_IFMT_ARGB32, w, h);
+
+    xmb_rt->surface_ptn =
+	mbe_pattern_create_for_surface(xmb_rt->surface);
     
     xmb_rt->backend_surface =
 	mbe_xlib_surface_create(xmb_rt->display,
@@ -476,7 +484,7 @@
     xmb_rt->cr = mbe_create(xmb_rt->surface);
     xmb_rt->backend_cr = mbe_create(xmb_rt->backend_surface);
 
-    mbe_set_source_surface(xmb_rt->backend_cr, xmb_rt->surface, 0, 0);
+    mbe_set_source(xmb_rt->backend_cr, xmb_rt->surface_ptn);
 
     xmb_rt->rdman = (redraw_man_t *)malloc(sizeof(redraw_man_t));
     redraw_man_init(xmb_rt->rdman, xmb_rt->cr, xmb_rt->backend_cr);
@@ -522,6 +530,8 @@
 
     if(xmb_rt->surface)
 	mbe_surface_destroy(xmb_rt->surface);
+    if(xmb_rt->surface_ptn)
+	mbe_pattern_destroy(xmb_rt->surface_ptn);
     if(xmb_rt->backend_surface)
 	mbe_surface_destroy(xmb_rt->backend_surface);
 
@@ -540,8 +550,10 @@
 	return NULL;
 
     r = X_MB_init(display_name, w, h, rt);
-    if(r != OK)
+    if(r != OK) {
+	free(rt);
 	return NULL;
+    }
 
     return rt;
 }
@@ -583,7 +595,7 @@
     return img_ldr;
 }
 
-void X_add_event(void *rt, int type, int fd, mb_eventcb_t f,void *arg)
+void X_MB_add_event(void *rt, int type, int fd, mb_eventcb_t f,void *arg)
 {
     X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt;
     int i;
@@ -613,7 +625,7 @@
     xmb_rt->n_monitor=i;
 }
 
-void X_remove_event(void *rt, int type, int fd)
+void X_MB_remove_event(void *rt, int type, int fd)
 {
     X_MB_runtime_t *xmb_rt = (X_MB_runtime_t *) rt;
     int i;
@@ -626,8 +638,8 @@
 }
 mb_backend_t backend = { X_MB_new,
 			 X_MB_free,
-			 X_add_event,
-			 X_remove_event,
+			 X_MB_add_event,
+			 X_MB_remove_event,
 			 X_MB_handle_connection,
 			 X_MB_kbevents,
 			 X_MB_rdman,
@@ -635,4 +647,27 @@
 			 X_MB_ob_factory,
 			 X_MB_img_ldr
 		};
-			 
+/*! \defgroup x_supp_nodejs_sup Export functions for supporting nodejs plugin.
+ *
+ * These functions are for internal using.
+ * @{
+ */			 
+/*! \brief Exported for nodejs plugin to call handle_x_event.
+ */
+void _X_MB_handle_x_event_for_nodejs(void *rt) {
+    handle_x_event((X_MB_runtime_t *)rt);
+}
+
+/*! \brief Get X connect for nodejs plugin.
+ */
+int _X_MB_get_x_conn_for_nodejs(void *rt) {
+    return XConnectionNumber(((X_MB_runtime_t *)rt)->display);
+}
+
+/*! \brief Flush buffer for the X connection of a runtime object.
+ */
+int _X_MB_flush_x_conn_for_nodejs(void *rt) {
+    return XFlush(((X_MB_runtime_t *)rt)->display);
+}
+
+/* @} */
--- a/src/coord.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/coord.c	Wed Jun 09 17:30:09 2010 +0800
@@ -63,7 +63,7 @@
  * matrix as aggregated matrix. 
  */
 static void compute_transform_function(coord_t *visit) {
-    if(visit->parent)
+    if(!coord_is_root(visit))
 	mul_matrix(visit->parent->aggr_matrix,
 		   visit->matrix, visit->aggr_matrix);
     else
@@ -83,7 +83,7 @@
     co_aix cache_p_matrix[6];
     co_aix cache_scale_x, cache_scale_y;
     
-    if(visit->parent) {
+    if(!coord_is_root(visit)) {
 	p_matrix = coord_get_aggr_matrix(visit->parent);
 	cache_scale_x =
 	    sqrtf(p_matrix[0] * p_matrix[0] + p_matrix[3] * p_matrix[3]);
@@ -105,6 +105,14 @@
     compute_transform_function_cached(coord);
 }
 
+void
+compute_aggr(coord_t *coord) {
+    if(coord->flags & COF_OWN_CANVAS)
+	compute_transform_function_cached(coord);
+    else
+	compute_transform_function(coord);
+}
+
 void compute_reverse(co_aix *orig, co_aix *reverse) {
     co_aix working[6];
     co_aix factor;
--- a/src/event.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/event.c	Wed Jun 09 17:30:09 2010 +0800
@@ -9,7 +9,7 @@
 #include "mb_redraw_man.h"
 #include "mb_shapes.h"
 #endif
-#include "../config.h"
+#include "config.h"
 
 #define OK 0
 #define ERR -1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/graph_engine_cairo.c	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,154 @@
+#include <fontconfig/fontconfig.h>
+#include <cairo-ft.h>
+#include "mb_graph_engine_cairo.h"
+#include "mb_shapes.h"
+
+#ifndef ASSERT
+#define ASSERT(x)
+#endif
+
+/*! \brief Find out a font pattern.
+ *
+ * This function use fontconfig to decide a font file in pattern.  It can
+ * replaced by other mechanism if you think it is not what you want.
+ *
+ * \param slant make font prune if it it non-zero.
+ * \param weight make font normal if it is 100.
+ */
+static
+FcPattern *query_font_pattern(const char *family, int slant, int weight) {
+    FcPattern *ptn, *p, *fn_ptn;
+    FcValue val;
+    FcConfig *cfg;
+    FcBool r;
+    FcResult result;
+    static int slant_map[] = {	/* from MB_FONT_SLANT_* to FC_SLANT_* */
+	FC_SLANT_ROMAN,
+	FC_SLANT_ROMAN,
+	FC_SLANT_ITALIC,
+	FC_SLANT_OBLIQUE};
+
+    cfg = FcConfigGetCurrent();
+    ptn = FcPatternCreate();
+    p = FcPatternCreate();
+    if(ptn == NULL || p == NULL)
+	goto err;
+
+    val.type = FcTypeString;
+    val.u.s = family;
+    FcPatternAdd(ptn, "family", val, FcTrue);
+    
+    val.type = FcTypeInteger;
+    val.u.i = slant_map[slant];
+    FcPatternAdd(ptn, "slant", val, FcTrue);
+    
+    val.type = FcTypeInteger;
+    val.u.i = weight;
+    FcPatternAdd(ptn, "weight", val, FcTrue);
+
+    r = FcConfigSubstituteWithPat(cfg, ptn, NULL, FcMatchPattern);
+    if(!r)
+	goto err;
+    
+    r = FcConfigSubstituteWithPat(cfg, p, ptn, FcMatchFont);
+    if(!r)
+	goto err;
+
+    FcDefaultSubstitute(p);
+
+    fn_ptn = FcFontMatch(cfg, p, &result);
+
+    /* It is supposed to return FcResultMatch.  But, it is no, now.
+     * I don't know why.  Someone should figure out the issue.
+     */
+#if 0
+    if(result != FcResultMatch) {
+	printf("%d %d\n", result, FcResultMatch);
+	goto err;
+    }
+#endif
+    if(fn_ptn == NULL)
+	goto err;
+
+    FcPatternDestroy(ptn);
+    FcPatternDestroy(p);
+    
+    return fn_ptn;
+    
+err:
+    if(ptn)
+	FcPatternDestroy(ptn);
+    if(p)
+	FcPatternDestroy(p);
+    return NULL;
+
+}
+
+/*! \brief Find out a font face for a pattern specified.
+ *
+ * The pattern, here, is a vector of family, slant, and weight.
+ * This function base on fontconfig and cairo FreeType font supporting.
+ * You can replace this function with other font mechanisms.
+ */
+mbe_font_face_t *
+mbe_query_font_face(const char *family, int slant, int weight) {
+    mbe_font_face_t *cface;
+    FcPattern *ptn;
+    
+    ptn = query_font_pattern(family, slant, weight);
+    cface = cairo_ft_font_face_create_for_pattern(ptn);
+    FcPatternDestroy(ptn);
+    
+    return cface;
+}
+
+void
+mbe_free_font_face(mbe_font_face_t *face) {
+    ASSERT(face == NULL);
+
+    mbe_font_face_destroy(face);
+}
+
+mbe_pattern_t *
+mbe_pattern_create_radial(co_aix cx0, co_aix cy0, co_aix radius0,
+			  co_aix cx1, co_aix cy1, co_aix radius1,
+			  grad_stop_t *stops, int stop_cnt) {
+    cairo_pattern_t *ptn;
+    grad_stop_t *stop;
+    int i;
+
+    ptn = cairo_pattern_create_radial(cx0, cy0, radius0,
+				      cx1, cy1, radius1);
+    if(ptn == NULL)
+	return NULL;
+    
+    stop = stops;
+    for(i = 0; i < stop_cnt; i++) {
+	cairo_pattern_add_color_stop_rgba(ptn, stop->offset,
+					  stop->r, stop->g, stop->b, stop->a);
+	stop++;
+    }
+
+    return ptn;
+}
+
+mbe_pattern_t *
+mbe_pattern_create_linear(co_aix x0, co_aix y0, co_aix x1, co_aix y1,
+			  grad_stop_t *stops, int stop_cnt) {
+    cairo_pattern_t *ptn;
+    grad_stop_t *stop;
+    int i;
+
+    ptn = cairo_pattern_create_linear(x0, y0, x1, y1);
+    if(ptn == NULL)
+	return NULL;
+
+    stop = stops;
+    for(i = 0; i < stop_cnt; i++) {
+	cairo_pattern_add_color_stop_rgba(ptn, stop->offset,
+					  stop->r, stop->g, stop->b, stop->a);
+	stop++;
+    }
+
+    return ptn;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/graph_engine_skia.cpp	Wed Jun 09 17:30:09 2010 +0800
@@ -0,0 +1,869 @@
+/*! \page ge_layer Graphic Engine Layer
+ *
+ * Graphic Engine Layer is an abstract of graphic engine; likes Cairo
+ * and Skia.  It provides portability for the rest of MadButterfly.
+ *
+ * The basic stratage of interface of graphic engine layer is defined
+ * according purpose of MadButterfly.  For example, MadButterfly wants
+ * a function that can clear a canvas, we define a clear function.
+ * Never define a indirectly way to finish the function.  Never define
+ * a way to finish the function for the reason that some engine
+ * require you to finish the task in that procedure.  It avoids
+ * binding graphic engine layer with any behavior of a graphic engine,
+ * and provides more compatible with other engines, to define
+ * interface of graphic engine layer according purpose of
+ * MadButterfly.
+ *
+ * \section ge_mem Graphic Engine Layer Memory Management
+ *
+ * MadButterfly is responsible for management of objects and memory
+ * blocks returned by graphic engine layer, even for graphic engines
+ * that have management model.  MadButterfly supposes memory blocks
+ * only be released when they are no more used.  MadBufferfly is
+ * responsible for release them.  So, even a graphic engine has
+ * reference count with objects, MadButterfly still keep a reference
+ * for every object returned by the engine until no one will use it.
+ *
+ * \section ge_transform Transformation of Coordination System
+ *
+ * Points of pathes are transformed when it is added to the canvas
+ * with the transformation matrix at the time.  So, changes of
+ * transformation matrix of an canvas will not affect points that had
+ * been added.  It only affects points been added when the matrix is
+ * setted.
+ */
+#include <stdio.h>
+#include <SkCanvas.h>
+#include <SkBitmap.h>
+#include <SkRegion.h>
+#include <SkShader.h>
+#include <SkDevice.h>
+#include <SkGradientShader.h>
+#include <SkXfermode.h>
+#include <SkColorFilter.h>
+
+#define C_START extern "C" {
+#define C_END }
+
+C_START
+
+#include "mb_graph_engine_skia.h"
+#include "mb_shapes.h"
+#include "mb_img_ldr.h"
+
+/*! \brief Source pattern
+ *
+ * For Skia, source pattern is SkShader with some decoration.  Since
+ * SkShade will repeative tiling or extenting edge color, it can not
+ * stop tiling and extenting for fixed size bitmap.  So, we need to
+ * translate mbe_paint() into a drawing of a rectangle.
+ */
+struct _mbe_pattern_t {
+    SkShader *shader;
+    int w, h;
+    int has_size;
+    co_aix matrix[6];
+};
+
+struct _mbe_scaled_font_t {
+    struct _mb_font_face_t *face;
+    co_aix fnt_mtx[6];
+    co_aix ctm[6];
+};
+struct _mbe_font_face_t {};
+/*! \brief MadButterfly Graphic Engine Context.
+ *
+ * A context comprises source pattern, target surface, path,
+ * line-width, and transform matrix.
+ */
+struct _mbe_t {
+    SkCanvas *canvas;
+    SkPath *path, *subpath;
+    SkPaint *paint;
+    SkRegion *saved_region;
+    
+    struct _mbe_states_t *states;
+};
+
+struct _mbe_states_t {
+    mbe_pattern_t *ptn;
+    int ptn_owned;
+    co_aix line_width;
+    co_aix matrix[6];
+    struct _mbe_states_t *next;
+};
+
+#ifndef ASSERT
+#define ASSERT(x)
+#endif
+
+#define PI 3.1415926535897931
+
+#define CO_AIX_2_SKSCALAR(a) ((SkScalar)a)
+#define SKSCALAR_2_CO_AIX(a) ((co_aix)(a))
+#define MB_MATRIX_2_SKMATRIX(sk, mb) {			\
+	(sk).setScaleX(CO_AIX_2_SKSCALAR((mb)[0]));	\
+	(sk).setSkewX(CO_AIX_2_SKSCALAR((mb)[1]));	\
+	(sk).setTranslateX(CO_AIX_2_SKSCALAR((mb)[2]));	\
+	(sk).setSkewY(CO_AIX_2_SKSCALAR((mb)[3]));	\
+	(sk).setScaleY(CO_AIX_2_SKSCALAR((mb)[4]));	\
+	(sk).setTranslateY(CO_AIX_2_SKSCALAR((mb)[5]));	\
+	(sk).setPerspX(0);				\
+	(sk).setPerspY(0);				\
+	(sk).set(SkMatrix::kMPersp2, 1);		\
+    }
+#define SKMATRIX_2_MB_MATRIX(mb, sk) {				\
+	(mb)[0] = SKSCALAR_2_CO_AIX((sk).getScaleX());		\
+	(mb)[1] = SKSCALAR_2_CO_AIX((sk).getSkewX());		\
+	(mb)[2] = SKSCALAR_2_CO_AIX((sk).getTranslateX());	\
+	(mb)[3] = SKSCALAR_2_CO_AIX((sk).getSkewY());		\
+	(mb)[4] = SKSCALAR_2_CO_AIX((sk).getScaleY());		\
+	(mb)[5] = SKSCALAR_2_CO_AIX((sk).getTranslateY());	\
+    }
+#define MBSTOP_2_SKCOLOR(c)			\
+    ((((int)((c)->a * 255)) << 24) |		\
+     (((int)((c)->r * 255)) << 16) |		\
+     (((int)((c)->g * 255)) << 8) |		\
+     (((int)((c)->b * 255))))
+#define MB_CO_COMP_2_SK(c) (((int)((c) * 255)) & 0xff)
+
+static const co_aix id_matrix[6] = { 1, 0, 0, 0, 1, 0 };
+
+static void
+_prepare_sized_pattern(mbe_t *mbe, mbe_pattern_t *ptn) {
+    SkCanvas *canvas = mbe->canvas;
+    SkPath path;
+    co_aix x, y;
+    co_aix reverse[6];
+    
+    *mbe->saved_region = canvas->getTotalClip();
+    
+    compute_reverse(ptn->matrix, reverse);
+    x = 0; y = 0;
+    matrix_trans_pos(reverse, &x, &y);
+    path.moveTo(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y));
+    x = 0; y = ptn->h;
+    matrix_trans_pos(reverse, &x, &y);
+    path.moveTo(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y));
+    x = ptn->w; y = ptn->h;
+    matrix_trans_pos(reverse, &x, &y);
+    path.moveTo(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y));
+    path.close();
+    
+    canvas->clipPath(path, SkRegion::kIntersect_Op);
+}
+
+static void
+_finish_sized_pattern(mbe_t *mbe) {
+    SkCanvas *canvas = mbe->canvas;
+    
+    canvas->setClipRegion(*mbe->saved_region);
+}
+
+static void
+_canvas_device_region(SkCanvas *canvas, SkRegion *region) {
+    SkDevice *device;
+    int w, h;
+
+    device = canvas->getDevice();
+    w = device->width();
+    h = device->height();
+    region->setRect(0, 0, w, h);
+}
+
+static void
+_update_path(mbe_t *mbe) {
+    SkPath *path = mbe->path;
+    SkPath *subpath = mbe->subpath;
+    SkMatrix canvas_matrix;
+    SkPoint point;
+
+    MB_MATRIX_2_SKMATRIX(canvas_matrix, mbe->states->matrix);
+    path->addPath(*subpath, canvas_matrix);
+    
+    subpath->getLastPt(&point);
+    subpath->rewind();
+    subpath->moveTo(point);
+}
+
+/*
+ * When a function want to use the paint associated with a canvas to
+ * draw, it should call _prepare_paint() can make the paint ready.
+ * And, call _finish_paint() when the paint is no more used.
+ */
+static void
+_prepare_paint(mbe_t *mbe, SkPaint::Style style) {
+    SkPaint *paint = mbe->paint;
+    mbe_pattern_t *ptn = mbe->states->ptn;
+    SkShader *shader;
+    co_aix matrix[6];
+    SkMatrix skmatrix;
+
+    paint->setStyle(style);
+    
+    if(ptn != NULL) {
+	/* Local matrix of SkShader is a mapping from source pattern to
+	 * user space.  Unlikely, for Cairo is a mapping from user space
+	 * to source pattern.
+	 */
+	shader = ptn->shader;
+	matrix_mul(mbe->states->matrix, ptn->matrix, matrix);
+	MB_MATRIX_2_SKMATRIX(skmatrix, matrix);
+	shader->setLocalMatrix(skmatrix);
+	paint->setShader(shader);
+    }
+
+    if(style == SkPaint::kStroke_Style)
+	paint->setStrokeWidth(CO_AIX_2_SKSCALAR(mbe->states->line_width));
+
+    if(ptn != NULL && ptn->has_size)
+	_prepare_sized_pattern(mbe, ptn);
+}
+
+static void
+_finish_paint(mbe_t *mbe) {
+    mbe_pattern_t *ptn = mbe->states->ptn;
+    
+    mbe->paint->reset();
+    if(ptn != NULL && ptn->has_size)
+	_finish_sized_pattern(mbe);
+}
+
+mbe_pattern_t *mbe_pattern_create_for_surface(mbe_surface_t *surface) {
+    mbe_pattern_t *ptn;
+    SkBitmap *bitmap = (SkBitmap *)surface;
+
+    ptn = (mbe_pattern_t *)malloc(sizeof(mbe_pattern_t));
+    ptn->shader = SkShader::CreateBitmapShader(*bitmap,
+					       SkShader::kClamp_TileMode,
+					       SkShader::kClamp_TileMode);
+    if(ptn->shader == NULL) {
+	free(ptn);
+	return NULL;
+    }
+    
+    ptn->has_size = 1;
+    ptn->w = bitmap->width();
+    ptn->h = bitmap->height();
+
+    memcpy(ptn->matrix, id_matrix, sizeof(co_aix) * 6);
+    
+    return ptn;
+}
+
+mbe_pattern_t *
+mbe_pattern_create_radial(co_aix cx0, co_aix cy0, co_aix radius0,
+			  co_aix cx1, co_aix cy1, co_aix radius1,
+			  grad_stop_t *stops, int stop_cnt) {
+    mbe_pattern_t *ptn;
+    SkColor *colors;
+    SkScalar *poses;
+    grad_stop_t *stop;
+    SkPoint center;
+    int i;
+
+    ptn = (mbe_pattern_t *)malloc(sizeof(mbe_pattern_t));
+    colors = new SkColor[stop_cnt];
+    poses = new SkScalar[stop_cnt];
+    if(ptn == NULL || colors == NULL || poses == NULL)
+	goto fail;
+
+    center.set(CO_AIX_2_SKSCALAR(cx1), CO_AIX_2_SKSCALAR(cy1));
+    
+    stop = stops;
+    for(i = 0; i < stop_cnt; i++) {
+	colors[i] = MBSTOP_2_SKCOLOR(stop);
+	poses[i] = CO_AIX_2_SKSCALAR(stop->offset);
+    }
+
+    /*
+     * cx0, cy0 and radius0 is not used.  Since Skia is still not
+     * support two circles radial.  And, SVG 1.2 is also not support
+     * two circles.
+     */
+    ptn->shader =
+	SkGradientShader::CreateRadial(center, CO_AIX_2_SKSCALAR(radius1),
+				       colors, poses, stop_cnt,
+				       SkShader::kClamp_TileMode);
+    if(ptn->shader == NULL)
+	goto fail;
+
+    memcpy(ptn->matrix, id_matrix, sizeof(co_aix) * 6);
+    
+    delete colors;
+    delete poses;
+    return ptn;
+    
+ fail:
+    if(ptn) free(ptn);
+    if(colors) delete colors;
+    if(poses) delete poses;
+    return NULL;
+}
+
+mbe_pattern_t *
+mbe_pattern_create_linear(co_aix x0, co_aix y0,
+			  co_aix x1, co_aix y1,
+			  grad_stop_t *stops, int stop_cnt) {
+    mbe_pattern_t *ptn;
+    SkColor *colors;
+    SkScalar *poses;
+    grad_stop_t *stop;
+    SkPoint points[2];
+    int i;
+
+    ptn = (mbe_pattern_t *)malloc(sizeof(mbe_pattern_t));
+    colors = new SkColor[stop_cnt];
+    poses = new SkScalar[stop_cnt];
+    if(ptn == NULL || colors == NULL || poses == NULL)
+	goto fail;
+
+    points[0].set(CO_AIX_2_SKSCALAR(x0), CO_AIX_2_SKSCALAR(y0));
+    points[1].set(CO_AIX_2_SKSCALAR(x1), CO_AIX_2_SKSCALAR(y1));
+    
+    stop = stops;
+    for(i = 0; i < stop_cnt; i++) {
+	colors[i] = MBSTOP_2_SKCOLOR(stop);
+	poses[i] = CO_AIX_2_SKSCALAR(stop->offset);
+    }
+
+    /*
+     * cx0, cy0 and radius0 is not used.  Since Skia is still not
+     * support two circles radial.  And, SVG 1.2 is also not support
+     * two circles.
+     */
+    ptn->shader =
+	SkGradientShader::CreateLinear(points, colors, poses, stop_cnt,
+				       SkShader::kClamp_TileMode);
+    if(ptn->shader == NULL)
+	goto fail;
+
+    memcpy(ptn->matrix, id_matrix, sizeof(co_aix) * 6);
+    
+    delete colors;
+    delete poses;
+    return ptn;
+    
+ fail:
+    if(ptn) free(ptn);
+    if(colors) delete colors;
+    if(poses) delete poses;
+    return NULL;
+}
+
+void mbe_pattern_set_matrix(mbe_pattern_t *ptn, const co_aix matrix[6]) {
+    SkMatrix skmatrix;
+
+    MB_MATRIX_2_SKMATRIX(skmatrix, matrix);
+
+    ptn->shader->setLocalMatrix(skmatrix);
+}
+
+void mbe_pattern_destroy(mbe_pattern_t *ptn) {
+    if(ptn->shader)
+	delete ptn->shader;
+    free(ptn);
+}
+
+int mbe_image_surface_get_stride(mbe_surface_t *surface) {
+    return ((SkBitmap *)surface)->rowBytes();
+}
+
+int mbe_image_surface_get_height(mbe_surface_t *surface) {
+    return ((SkBitmap *)surface)->height();
+}
+
+int mbe_image_surface_get_width(mbe_surface_t *surface) {
+    return ((SkBitmap *)surface)->width();
+}
+
+unsigned char *mbe_image_surface_get_data(mbe_surface_t *surface) {
+    return (unsigned char *)((SkBitmap *)surface)->getPixels();
+}
+
+mbe_surface_t *mbe_image_surface_create_from_png(const char *filename) {}
+
+mbe_surface_t *
+mbe_image_surface_create_for_data(unsigned char *data,
+				  mb_img_fmt_t fmt,
+				  int width, int height,
+				  int stride) {
+    SkBitmap *bitmap;
+    SkBitmap::Config cfg;
+
+    switch(fmt) {
+    case MB_IFMT_ARGB32:
+	cfg = SkBitmap::kARGB_8888_Config; break;
+	
+    case MB_IFMT_A8:
+	cfg = SkBitmap::kA8_Config; break;
+	
+    case MB_IFMT_A1:
+	cfg = SkBitmap::kA1_Config; break;
+	
+    case MB_IFMT_RGB16_565:
+	cfg = SkBitmap::kRGB_565_Config; break;
+	
+    case MB_IFMT_RGB24:
+    default:
+	return NULL;
+    }
+    
+    bitmap = new SkBitmap();
+    if(bitmap == NULL)
+	return NULL;
+    
+    bitmap->setConfig(cfg, width, height, stride);
+    bitmap->setPixels(data);
+
+    return (mbe_surface_t *)bitmap;
+}
+
+mb_img_fmt_t mbe_image_surface_get_format(mbe_surface_t *surface) {
+    SkBitmap *bitmap = (SkBitmap *)surface;
+    mb_img_fmt_t fmt;
+    SkBitmap::Config cfg;
+    
+    cfg = bitmap->getConfig();
+    switch(cfg) {
+    case SkBitmap::kARGB_8888_Config:
+	fmt = MB_IFMT_ARGB32; break;
+
+    case SkBitmap::kA8_Config:
+	fmt = MB_IFMT_A8; break;
+
+    case SkBitmap::kA1_Config:
+	fmt = MB_IFMT_A1; break;
+
+    case SkBitmap::kRGB_565_Config:
+	fmt = MB_IFMT_RGB16_565; break;
+
+    default:
+	fmt = MB_IFMT_DUMMY;
+    }
+
+    return fmt;
+}
+
+mbe_surface_t *
+mbe_image_surface_create(mb_img_fmt_t fmt, int width, int height) {
+    SkBitmap *bitmap;
+    SkBitmap::Config cfg;
+
+    switch(fmt) {
+    case MB_IFMT_ARGB32:
+	cfg = SkBitmap::kARGB_8888_Config; break;
+	
+    case MB_IFMT_A8:
+	cfg = SkBitmap::kA8_Config; break;
+	
+    case MB_IFMT_A1:
+	cfg = SkBitmap::kA1_Config; break;
+	
+    case MB_IFMT_RGB16_565:
+	cfg = SkBitmap::kRGB_565_Config; break;
+	
+    case MB_IFMT_RGB24:
+    default:
+	return NULL;
+    }
+    
+    bitmap = new SkBitmap();
+    if(bitmap == NULL)
+	return NULL;
+    
+    bitmap->setConfig(cfg, width, height);
+    bitmap->allocPixels();
+
+    return (mbe_surface_t *)bitmap;
+}
+
+mbe_scaled_font_t *mbe_scaled_font_reference(mbe_scaled_font_t *scaled) {
+}
+
+void mbe_scaled_font_destroy(mbe_scaled_font_t *scaled) {}
+mbe_font_face_t *mbe_font_face_reference(mbe_font_face_t *face) {}
+mbe_scaled_font_t *
+mbe_scaled_font_create(mbe_font_face_t *face, co_aix fnt_mtx[6],
+		       co_aix ctm[6]) {}
+mbe_scaled_font_t *mbe_get_scaled_font(mbe_t *canvas) {}
+void mbe_scaled_font_text_extents(mbe_scaled_font_t *scaled,
+					 const char *txt,
+					 mbe_text_extents_t *extents) {}
+
+void mbe_font_face_destroy(mbe_font_face_t *face) {}
+
+void mbe_paint_with_alpha(mbe_t *canvas, co_aix alpha) {
+    SkPaint *paint = canvas->paint;
+    SkColorFilter *filter;
+    SkColor color;
+
+    color = ((uint32_t)(alpha * 255)) << 24;
+    filter =
+	SkColorFilter::CreatePorterDuffFilter(color,
+					      SkPorterDuff::kSrcOver_Mode);
+    mbe_paint(canvas);
+    
+}
+
+void mbe_surface_destroy(mbe_surface_t *surface) {
+    SkBitmap *bmap = (SkBitmap *)surface;
+    
+    delete bmap;
+}
+
+void mbe_set_source_rgba(mbe_t *canvas,
+			 co_aix r, co_aix g, co_aix b, co_aix a) {
+    canvas->paint->setARGB(MB_CO_COMP_2_SK(a),
+			   MB_CO_COMP_2_SK(r),
+			   MB_CO_COMP_2_SK(g),
+			   MB_CO_COMP_2_SK(b));
+    canvas->states->ptn = NULL;
+}
+
+void mbe_set_scaled_font(mbe_t *canvas,
+				const mbe_scaled_font_t *scaled) {}
+void mbe_set_source_rgb(mbe_t *canvas, co_aix r, co_aix g, co_aix b) {}
+
+void mbe_set_line_width(mbe_t *canvas, co_aix width) {
+    canvas->states->line_width = width;
+}
+
+mbe_font_face_t *mbe_get_font_face(mbe_t *canvas) {}
+
+void mbe_fill_preserve(mbe_t *canvas) {
+    mbe_pattern_t *ptn = canvas->states->ptn;
+    SkPaint *paint = canvas->paint;
+    SkPath *path = canvas->path;
+    SkRegion *saved_clip = NULL;
+    co_aix x, y;
+
+    ASSERT(paint);
+    ASSERT(ptn);
+    ASSERT(path);
+
+    if(!canvas->subpath->isEmpty())
+	_update_path(canvas);
+    
+    _prepare_paint(canvas, SkPaint::kFill_Style);
+
+    canvas->canvas->drawPath(*path, *paint);
+
+    _finish_paint(canvas);
+}
+
+void mbe_set_source(mbe_t *canvas, mbe_pattern_t *source) {
+    canvas->states->ptn = source;
+}
+
+void mbe_reset_clip(mbe_t *canvas) {
+    SkRegion clip;
+
+    _canvas_device_region(canvas->canvas, &clip);
+    canvas->canvas->setClipRegion(clip);
+}
+
+mbe_surface_t *mbe_get_target(mbe_t *canvas) {
+    return (mbe_surface_t *)&canvas->canvas->getDevice()->accessBitmap(false);
+}
+
+void mbe_close_path(mbe_t *canvas) {
+    canvas->subpath->close();
+}
+
+void mbe_text_path(mbe_t *canvas, const char *txt) {}
+
+void mbe_rectangle(mbe_t *canvas, co_aix x, co_aix y,
+			  co_aix width, co_aix height) {
+    SkPath *subpath = canvas->subpath;
+    
+    subpath->addRect(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y),
+		     CO_AIX_2_SKSCALAR(x + width),
+		     CO_AIX_2_SKSCALAR(y + height));
+}
+
+int mbe_in_stroke(mbe_t *canvas, co_aix x, co_aix y) {
+    return 0;
+}
+
+void mbe_new_path(mbe_t *canvas) {
+    canvas->subpath->rewind();
+    canvas->path->rewind();
+}
+
+void mbe_curve_to(mbe_t *canvas, co_aix x1, co_aix y1,
+			 co_aix x2, co_aix y2,
+			 co_aix x3, co_aix y3) {
+    SkPath *subpath = canvas->subpath;
+
+    subpath->cubicTo(CO_AIX_2_SKSCALAR(x1), CO_AIX_2_SKSCALAR(y1),
+		     CO_AIX_2_SKSCALAR(x2), CO_AIX_2_SKSCALAR(y2),
+		     CO_AIX_2_SKSCALAR(x3), CO_AIX_2_SKSCALAR(y3));
+}
+
+void mbe_restore(mbe_t *canvas) {
+    struct _mbe_states_t *states;
+
+    _update_path(canvas);
+    
+    states = canvas->states;
+    ASSERT(states->next);
+    canvas->states = states->next;
+    free(states);
+}
+
+void mbe_move_to(mbe_t *canvas, co_aix x, co_aix y) {
+    canvas->subpath->moveTo(CO_AIX_2_SKSCALAR(x),
+			 CO_AIX_2_SKSCALAR(y));
+}
+
+void mbe_line_to(mbe_t *canvas, co_aix x, co_aix y) {
+    canvas->subpath->lineTo(CO_AIX_2_SKSCALAR(x),
+			    CO_AIX_2_SKSCALAR(y));
+}
+
+int mbe_in_fill(mbe_t *canvas, co_aix x, co_aix y) {
+    SkRegion region, dev_region;
+    bool in_fill;
+
+    if(!canvas->subpath->isEmpty())
+	_update_path(canvas);
+    
+    _canvas_device_region(canvas->canvas, &dev_region);
+    region.setPath(*canvas->path, dev_region);
+    
+    in_fill = region.contains(x, y);
+
+    return in_fill;
+}
+
+void mbe_stroke(mbe_t *canvas) {
+    SkPath *path = canvas->path;
+    SkPaint *paint = canvas->paint;
+
+    ASSERT(ptn);
+    ASSERT(path);
+    ASSERT(paint);
+
+    if(!canvas->subpath->isEmpty())
+	_update_path(canvas);
+
+    _prepare_paint(canvas, SkPaint::kStroke_Style);
+
+    canvas->canvas->drawPath(*path, *paint);
+
+    _finish_paint(canvas);
+
+    path->rewind();
+    canvas->subpath->rewind();
+}
+
+/*! \brief Create a mbe from a SkCanvas.
+ *
+ * It is only used for Android JNI.  It is used to create mbe_t from a
+ * SkCanvas created by Canvas class of Android Java application.
+ */
+mbe_t *skia_mbe_create_by_canvas(SkCanvas *canvas) {
+    mbe_t *mbe;
+    struct _mbe_states_t *states;
+
+    mbe = (mbe_t *)malloc(sizeof(mbe_t));
+    if(mbe == NULL)
+	return NULL;
+    
+    mbe->states = (struct _mbe_states_t *)
+	malloc(sizeof(struct _mbe_states_t));
+    states = mbe->states;
+    if(states == NULL) {
+	free(mbe);
+	return NULL;
+    }
+    
+    canvas->ref();
+    mbe->canvas = canvas;
+    mbe->path = new SkPath();
+    mbe->subpath = new SkPath();
+    mbe->saved_region = new SkRegion();
+    mbe->paint = new SkPaint();
+    states->ptn = NULL;
+    states->ptn_owned = 0;
+    states->line_width = 0;
+    states->next = NULL;
+
+    if(mbe->path == NULL ||
+       mbe->subpath == NULL || mbe->paint == NULL ||
+       mbe->saved_region == NULL)
+	goto fail;
+
+    memcpy(states->matrix, id_matrix, sizeof(co_aix) * 6);
+    
+    return mbe;
+
+ fail:
+    canvas->unref();
+    if(mbe->path) delete mbe->path;
+    if(mbe->subpath) delete mbe->subpath;
+    if(mbe->paint) delete mbe->paint;
+    if(mbe->saved_region) delete mbe->saved_region;
+    free(states);
+    free(mbe);
+    
+    return NULL;
+}
+
+mbe_t *mbe_create(mbe_surface_t *target) {
+    mbe_t *mbe;
+    SkBitmap *bitmap = (SkBitmap *)target;
+    SkCanvas *canvas;
+
+    canvas = new SkCanvas(*bitmap);
+    if(canvas == NULL) {
+	delete bitmap;
+	return NULL;
+    }
+	
+    mbe = skia_mbe_create_by_canvas(canvas);
+    canvas->unref();
+    
+    if(mbe == NULL) {
+	delete bitmap;
+    }
+    
+    return mbe;
+}
+
+void mbe_destroy(mbe_t *canvas) {
+    struct _mbe_states_t *states;
+    
+    canvas->canvas->unref();
+    delete canvas->path;
+    delete canvas->subpath;
+    delete canvas->paint;
+    delete canvas->saved_region;
+    while(canvas->states) {
+	states = canvas->states;
+	canvas->states = states->next;
+	
+	if(states->ptn && states->ptn_owned)
+	    mbe_pattern_destroy(states->ptn);
+	free(states);
+    }
+    free(canvas);
+}
+
+void mbe_paint(mbe_t *canvas) {
+    SkPaint *paint = canvas->paint;
+
+    ASSERT(paint);
+    
+    _prepare_paint(canvas, SkPaint::kFill_Style);
+    
+    canvas->canvas->drawPaint(*paint);
+
+    _finish_paint(canvas);
+}
+
+void mbe_save(mbe_t *canvas) {
+    struct _mbe_states_t *states;
+
+    states = (struct _mbe_states_t *)malloc(sizeof(struct _mbe_states_t));
+    ASSERT(states);
+    
+    memcpy(states, canvas->states, sizeof(struct _mbe_states_t));
+    states->next = canvas->states;
+    canvas->states = states;
+}
+
+void mbe_fill(mbe_t *canvas) {
+    mbe_fill_preserve(canvas);
+    canvas->path->rewind();
+    canvas->subpath->rewind();
+}
+
+void mbe_clip(mbe_t *canvas) {
+    if(!canvas->subpath->isEmpty())
+	_update_path(canvas);
+    
+    canvas->canvas->clipPath(*canvas->path, SkRegion::kIntersect_Op);
+    canvas->path->rewind();
+    canvas->subpath->rewind();
+}
+
+mbe_font_face_t * mbe_query_font_face(const char *family,
+					     int slant, int weight) {}
+void mbe_free_font_face(mbe_font_face_t *face) {}
+
+void mbe_clear(mbe_t *canvas) {
+    SkColor color = 0;
+
+    canvas->canvas->drawColor(color, SkPorterDuff::kClear_Mode);
+}
+
+void mbe_copy_source(mbe_t *src, mbe_t *dst) {
+    SkPaint *paint = dst->paint;
+    const SkBitmap *bmap;
+    SkXfermode *mode;
+
+    /* _prepare_paint(dst, SkPaint::kFill_Style); */
+    mode = SkPorterDuff::CreateXfermode(SkPorterDuff::kSrc_Mode);
+    paint->setXfermode(mode);
+    bmap = &src->canvas->getDevice()->accessBitmap(false);
+
+    dst->canvas->drawBitmap(*bmap, 0, 0, paint);
+    
+    paint->reset();
+    mode->unref();
+    /* _finish_paint(dst); */
+}
+
+void mbe_transform(mbe_t *mbe, co_aix matrix[6]) {
+    _update_path(mbe);
+    
+    matrix_mul(matrix, mbe->states->matrix, mbe->states->matrix);
+}
+
+void mbe_arc(mbe_t *mbe, co_aix x, co_aix y, co_aix radius,
+		    co_aix angle_start, co_aix angle_stop) {
+    SkPoint point;
+    SkPath *subpath = mbe->subpath;
+    SkRect rect;
+    SkScalar x0, y0;
+    SkScalar ang_start, ang_stop;
+    SkScalar sweep;
+    SkScalar r;			/* radius */
+
+    subpath->getLastPt(&point);
+    x0 = point.fX;
+    y0 = point.fX;
+    r = CO_AIX_2_SKSCALAR(radius);
+    ang_start = CO_AIX_2_SKSCALAR(angle_start * 180 / PI);
+    ang_stop = CO_AIX_2_SKSCALAR(angle_stop * 180 / PI);
+    
+    /* Skia can only draw an arc in clockwise directly.  We negative
+     * start and stop point to draw the arc in the mirror along x-axis
+     * in a sub-path.  Then, the sub-path are reflected along x-axis,
+     * again.  We get a right path, and add it to the path of mbe_t.
+     */
+    if(ang_start > ang_stop) {
+	SkPath tmppath;
+	SkMatrix matrix;
+	co_aix reflect[6] = { 1, 0, 0,
+			      0, -1, 0};
+	
+	rect.set(-r, -r, r, r);
+	sweep = ang_start - ang_stop;
+	tmppath.arcTo(rect, -ang_start, sweep, false);
+
+	reflect[2] = x;
+	reflect[5] = y;
+	MB_MATRIX_2_SKMATRIX(matrix, reflect);
+	subpath->addPath(tmppath, matrix);
+    } else {
+	rect.set(x0 - r, y0 - r, x0 + r, y0 + r);
+	sweep = ang_stop - ang_start;
+	subpath->arcTo(rect, ang_start, sweep, false);
+    }
+}
+
+
+C_END
--- a/src/paint.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/paint.c	Wed Jun 09 17:30:09 2010 +0800
@@ -92,13 +92,9 @@
 	    mbe_pattern_destroy(ptn);
 	linear->flags &= ~LIF_DIRTY;
 	ptn = mbe_pattern_create_linear(linear->x1, linear->y1,
-					  linear->x2, linear->y2);
-	for(i = 0; i < linear->n_stops; i++) {
-	    stop = &linear->stops[i];
-	    mbe_pattern_add_color_stop_rgba(ptn, stop->offset,
-					      stop->r, stop->g, stop->b,
-					      stop->a);
-	}
+					linear->x2, linear->y2,
+					linear->stops, linear->n_stops);
+	ASSERT(ptn != NULL);
 	linear->ptn = ptn;
     }
 
@@ -177,20 +173,15 @@
 static void paint_radial_prepare(paint_t *paint, mbe_t *cr) {
     paint_radial_t *radial = (paint_radial_t *)paint;
     mbe_pattern_t *ptn;
-    grad_stop_t *stop;
     int i;
 
     if(radial->flags & RDF_DIRTY) {
 	ptn = mbe_pattern_create_radial(radial->cx, radial->cy, 0,
 					  radial->cx, radial->cy,
-					  radial->r);
+					radial->r,
+					radial->stops,
+					radial->n_stops);
 	ASSERT(ptn != NULL);
-	stop = radial->stops;
-	for(i = 0; i < radial->n_stops; i++, stop++) {
-	    mbe_pattern_add_color_stop_rgba(ptn, stop->offset,
-					      stop->r, stop->g,
-					      stop->b, stop->a);
-	}
 	mbe_pattern_destroy(radial->ptn);
 	radial->ptn = ptn;
     }
@@ -328,15 +319,8 @@
  */
 void paint_image_set_matrix(paint_t *paint, co_aix matrix[6]) {
     paint_image_t *img_paint = (paint_image_t *)paint;
-    mbe_matrix_t cmatrix;
     
-    cmatrix.xx = matrix[0];
-    cmatrix.xy = matrix[1];
-    cmatrix.x0 = matrix[2];
-    cmatrix.yx = matrix[3];
-    cmatrix.yy = matrix[4];
-    cmatrix.y0 = matrix[5];
-    mbe_pattern_set_matrix(img_paint->ptn, &cmatrix);
+    mbe_pattern_set_matrix(img_paint->ptn, matrix);
 }
 
 void paint_image_get_size(paint_t *paint, int *w, int *h) {
--- a/src/redraw_man.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/redraw_man.c	Wed Jun 09 17:30:09 2010 +0800
@@ -9,7 +9,7 @@
 #include "mb_redraw_man.h"
 #include "mb_observer.h"
 #include "mb_prop.h"
-#include "../config.h"
+#include "config.h"
 
 /* required by rdman_img_ldr_load_paint() */
 #include "mb_paint.h"
@@ -39,7 +39,7 @@
  * Whenever a coord is marked dirty and put into redraw_man_t::dirty_coords
  * list, all it's children should also be marked.
  *
- * The procedure of clean coords comprises recomputing aggregate
+ * The procedure of clean coords comprises recomputing aggregated
  * transform matrix and area where members spreading in.  The aggregated
  * transform matrix can reduce number of matrix mul to transform
  * positions from space of a coord to the closest cached ancestor coord.
@@ -229,12 +229,12 @@
  *
  * \section cache_imp Implementation of Cache
  * Both cached coords and coords that opacity != 1 need a canvas to
- * draw descendants on.  Both cases are traded in the same way.
- * Every of them own a canvas_info to describe canvas and related
+ * draw descendants on.  Both cases are traded in the same way.  Every
+ * of them own a canvas_info to describe canvas and related
  * information.  aggr_matrix of descendants must be adjusted to make
- * left-top of range just at origin of canvas.  It can save space by setting
- * just large enough to hold rendering result of descendants.  The process
- * of adjusting is zeroing.
+ * left-top of bounding box just at origin (0, 0) of canvas.  It saves
+ * space to give a canvas just enough for rending descadants.  The
+ * process of adjusting left-top of bounding box is zeroing.
  *
  * Following is rules.
  * - zeroing on a cached coord is performed by adjust coord_t::aggr_matrix 
@@ -242,18 +242,20 @@
  * - Clean coords works just like before without change.
  *   - in preorder
  * - never perform zeroing on root_coord.
- * - zeroing on cached coords marked with \ref COF_MUST_ZEROING.
+ * - do zeroing on cached coords marked with \ref COF_MUST_ZEROING.
  *   - when clean a descendant that moves out-side of it's canvas,
  *     respective cached coord is marked with \ref COF_MUST_ZEROING.
  *   - zeroing is performed immediately after clean coords.
- *   - zeroing will not propagate acrossing boundary of cached coord.
- *     - It will be stopped at descendants which are cached coords.
+ *   - zeroing will not be propagated to ancestors of a cached coord.
+ *     - It will be stopped once a cached coord being found.
  *     - coord_t::cur_area and coord_t::aggr_matrix of cached coords
  *       must be ajdusted.
  * - the area of a cached coord is defined in parent space.
  *   - areas of descendants are defined in space defined by aggr_matrix of
  *     cached coord.
- *   - parent know the area in where cached coord and descendnats will
+ *     - coord_t::aggr_matrix of cached coord defines coordination of
+ *       descendants.
+ *   - the parent knows the area in where cached coord and descendnats will
  *     be draw.
  * - cached coords keep their private dirty area list.
  *   - private dirty areas of a cached coord are transformed and added to
@@ -285,14 +287,15 @@
  *   - Cached ancestors of zeroed ones should also be zeroed.
  * - zeroing
  *   - Add more dirty areas if canvas should be fully redrawed.
- *   - From leaf to root.
+ *   - From leaves to root.
+ *   - Adjust area of child cached coords.
  * - add aggregated dirty areas from descendant cached coords to ancestors.
  *   - Must include old area of cached coords if it is just clean and
  *     parent cached one is not just clean.
  *   - Just clean is a coord cleaned in last time of cleaning coords.
  * - draw dirty areas
  *   - areas are rounded to N at first.
- *   - from leaf to root.
+ *   - from leaves to root.
  */
 
 #ifndef ASSERT
@@ -370,8 +373,6 @@
 	(member) = STAILQ_NEXT(paint_t, next, member))
 #define RM_PAINTMEMBER(paint, member)				\
     STAILQ_REMOVE((paint)->members, shnode_t, next, member)
-#define RM_PAINT(rdman, paint)					\
-    STAILQ_REMOVE((rdman)->paints, paint_t, pnt_next, paint)
 
 /*! \brief Sort a list of element by a unsigned integer.
  *
@@ -456,6 +457,9 @@
 static int add_dirty_area(redraw_man_t *rdman, coord_t *coord, area_t *area) {
     int r;
     
+    if(area->w < 0.01 || area->h < 0.01)
+	return OK;
+    
     rdman->n_dirty_areas++;
     r = areas_add(_coord_get_dirty_areas(coord), area);
     return r == 0? OK: ERR;
@@ -467,6 +471,12 @@
     return OK;
 }
 
+static int add_dirty_pcache_area_coord(redraw_man_t *rdman, coord_t *coord) {
+    coord_set_flags(coord, COF_DIRTY_PCACHE_AREA);
+    ADD_DATA(coords, dirty_pcache_area_coords, coord);
+    return OK;
+}
+
 static int add_free_obj(redraw_man_t *rdman, void *obj,
 			free_func_t free_func) {
     int max;
@@ -586,6 +596,10 @@
     info->owner = coord;
     info->canvas = canvas;
     DARRAY_INIT(&info->dirty_areas);
+    
+    bzero(info->pcache_areas, sizeof(area_t) * 2);
+    info->pcache_cur_area = &info->pcache_areas[0];
+    info->pcache_last_area = &info->pcache_areas[1];
 
     return info;
 }
@@ -608,6 +622,7 @@
     memset(rdman, 0, sizeof(redraw_man_t));
 
     DARRAY_INIT(&rdman->dirty_coords);
+    DARRAY_INIT(&rdman->dirty_pcache_area_coords);
     DARRAY_INIT(&rdman->dirty_geos);
     DARRAY_INIT(&rdman->gen_geos);
     DARRAY_INIT(&rdman->zeroing_coords);
@@ -654,7 +669,7 @@
     rdman->root_coord->mouse_event = subject_new(&rdman->ob_factory,
 						 rdman->root_coord,
 						 OBJT_COORD);
-    rdman->root_coord->flags |= COF_OWN_CANVAS;
+    coord_set_flags(rdman->root_coord, COF_OWN_CANVAS);
     rdman->root_coord->canvas_info =
 	coord_canvas_info_new(rdman, rdman->root_coord, cr);
     rdman->root_coord->opacity = 1;
@@ -663,7 +678,6 @@
     rdman->backend = backend;
 
     STAILQ_INIT(rdman->shapes);
-    STAILQ_INIT(rdman->paints);
     
     /* \note To make root coord always have at leat one observer.
      * It triggers mouse interpreter to be installed on root.
@@ -694,6 +708,7 @@
     if(rdman->coord_canvas_pool)
 	elmpool_free(rdman->coord_canvas_pool);
     DARRAY_DESTROY(&rdman->dirty_coords);
+    DARRAY_DESTROY(&rdman->dirty_pcache_area_coords);
     DARRAY_DESTROY(&rdman->dirty_geos);
     DARRAY_DESTROY(&rdman->gen_geos);
     DARRAY_DESTROY(&rdman->zeroing_coords);
@@ -710,6 +725,13 @@
     free_free_objs(rdman);
     free_objs_destroy(rdman);
 
+    /* Mark rdman clean that shapes and coords can be freed
+     *  successfully.
+     */
+    DARRAY_CLEAN(&rdman->dirty_coords);
+    DARRAY_CLEAN(&rdman->dirty_pcache_area_coords);
+    DARRAY_CLEAN(&rdman->dirty_geos);
+
     coord = postorder_coord_subtree(rdman->root_coord, NULL);
     while(coord) {
 	saved_coord = coord;
@@ -719,27 +741,19 @@
 	}
 	rdman_coord_free(rdman, saved_coord);
     }
-#if 0
-    FORMEMBERS(saved_coord, member) {
-	rdman_shape_free(rdman, member->shape);
-    }
-#endif
     /* Resources of root_coord is free by elmpool_free() or
      * caller; for canvas
      */
 
-    shape = saved_shape = STAILQ_HEAD(rdman->shapes);
-    while(shape && (shape = STAILQ_NEXT(shape_t, sh_next, shape))) {
-	rdman_shape_free(rdman, saved_shape);
-#if 0
-	STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, saved_shape);
-#endif
-	saved_shape = shape;
+    while((shape = STAILQ_HEAD(rdman->shapes)) != NULL) {
+	rdman_shape_free(rdman, shape);
     }
-    if(saved_shape != NULL)
-	rdman_shape_free(rdman, saved_shape);
     
     coord_canvas_info_free(rdman, rdman->root_coord->canvas_info);
+
+    /* XXX: paints are not freed, here.  All resources of paints would
+     * be reclaimed by freeing elmpools.
+     */
     
     elmpool_free(rdman->coord_pool);
     elmpool_free(rdman->geo_pool);
@@ -751,6 +765,7 @@
     elmpool_free(rdman->coord_canvas_pool);
 
     DARRAY_DESTROY(&rdman->dirty_coords);
+    DARRAY_DESTROY(&rdman->dirty_pcache_area_coords);
     DARRAY_DESTROY(&rdman->dirty_geos);
     DARRAY_DESTROY(&rdman->gen_geos);
     DARRAY_DESTROY(&rdman->zeroing_coords);
@@ -835,6 +850,11 @@
 	return OK;
     }
 
+    if(shape->stroke != NULL)
+	rdman_paint_stroke(rdman, (paint_t *)NULL, shape);
+    if(shape->fill != NULL)
+	rdman_paint_fill(rdman, (paint_t *)NULL, shape);
+    
     if(geo != NULL) {
 	subject_free(geo->mouse_event);
 	geo_detach_coord(geo, shape->coord);
@@ -848,6 +868,7 @@
 
     if(rdman->last_mouse_over == (mb_obj_t *)shape)
 	rdman->last_mouse_over = NULL;
+
     
     return OK;
 }
@@ -865,6 +886,7 @@
 
 int rdman_paint_free(redraw_man_t *rdman, paint_t *paint) {
     shnode_t *shnode, *saved_shnode;
+    shape_t *shape;
 
     if(rdman_is_dirty(rdman)) {
 	if(!(paint->flags & PNTF_FREE))
@@ -879,16 +901,29 @@
     FORPAINTMEMBERS(paint, shnode) {
 	if(saved_shnode) {
 	    RM_PAINTMEMBER(paint, saved_shnode);
+	    
+	    shape = saved_shnode->shape;
+	    if(shape->stroke == paint)
+		rdman_paint_stroke(rdman, (paint_t *)NULL, shape);
+	    if(shape->fill == paint)
+		rdman_paint_fill(rdman, (paint_t *)NULL, shape);
+	    
 	    shnode_free(rdman, saved_shnode);
 	}
 	saved_shnode = shnode;
     }
     if(saved_shnode) {
 	RM_PAINTMEMBER(paint, saved_shnode);
+	
+	shape = saved_shnode->shape;
+	if(shape->stroke == paint)
+	    rdman_paint_stroke(rdman, (paint_t *)NULL, shape);
+	if(shape->fill == paint)
+	    rdman_paint_fill(rdman, (paint_t *)NULL, shape);
+	
 	shnode_free(rdman, saved_shnode);
     }
 
-    RM_PAINT(rdman, paint);
     paint->free(rdman, paint);
     return OK;
 }
@@ -1003,7 +1038,7 @@
 	return rdman_coord_free_postponse(rdman, coord);
 
     /* Free canvas and canvas_info (\ref redraw) */
-    if(coord->flags & COF_OWN_CANVAS) {
+    if(coord_is_cached(coord)) {
 	canvas_free(_coord_get_canvas(coord));
 	coord_canvas_info_free(rdman, coord->canvas_info);
     }
@@ -1076,6 +1111,9 @@
  * into dirty_coords list.  rdman_coord_changed() should be called
  * for a coord after it been changed to notify redraw manager to
  * redraw shapes grouped by it.
+ *
+ * Once a coord is changed, all its descendants are also put marked
+ * dirty.
  */
 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) {
     coord_t *child;
@@ -1099,12 +1137,12 @@
 	    continue;
 	}
 
-	add_dirty_coord(rdman, child);
-
-	if(child->flags & COF_OWN_CANVAS) {
+	if(coord_is_cached(child)) {
 	    preorder_coord_skip_subtree(child);
 	    continue;
 	}
+
+	add_dirty_coord(rdman, child);
     }
 
     return OK;
@@ -1205,16 +1243,16 @@
 	return;
 
     if(coord->opacity != 1 || coord_is_cached(coord)) {
-	if(!(coord->flags & COF_OWN_CANVAS)) {
+	if(!coord_is_cached(coord)) {
 	    /* canvas is assigned latter, in zeroing_coord() */
 	    coord->canvas_info = coord_canvas_info_new(rdman, coord, NULL);
-	    coord->flags |= COF_OWN_CANVAS;
+	    coord_set_flags(coord, COF_OWN_CANVAS);
 	}
     } else {
-	if(coord->flags & COF_OWN_CANVAS) {
+	if(coord_is_cached(coord)) {
 	    canvas_free(_coord_get_canvas(coord));
 	    coord_canvas_info_free(rdman, coord->canvas_info);
-	    coord->flags &= ~COF_OWN_CANVAS;
+	    coord_clear_flags(coord, COF_OWN_CANVAS);
 	}
 	/* This must here to keep coords that do not own canvas
 	 * can always point to right canvas_info.  Since, they
@@ -1224,20 +1262,95 @@
     }
 }
 
-static int coord_clean_members_n_compute_area(coord_t *coord) {
-    geo_t *geo;
-    /*! \note poses is shared by invokings, it is not support reentrying. */
+/* \brief Compute matrix from cached canvas to parent device space.
+ */
+static void compute_cached_2_pdev_matrix(coord_t *coord,
+					   co_aix canvas2pdev_matrix[6]) {
+    coord_t *parent;
+    co_aix *aggr;
+    co_aix *matrix, *paggr;
+    co_aix scale_x, scale_y;
+    co_aix shift_x, shift_y;
+    co_aix canvas2p[6];
+
+    aggr = coord_get_aggr_matrix(coord);
+    matrix = coord->matrix;
+    parent = coord->parent;
+    paggr = coord_get_aggr_matrix(parent);
+    
+    scale_x = matrix[0] / aggr[0];
+    scale_y = matrix[3] / aggr[3];
+    shift_x = matrix[2] - scale_x * aggr[2];
+    shift_y = matrix[5] - scale_y * aggr[5];
+
+    canvas2p[0] = scale_x;
+    canvas2p[1] = 0;
+    canvas2p[2] = shift_x;
+    canvas2p[3] = 0;
+    canvas2p[4] = scale_y;
+    canvas2p[5] = shift_y;
+
+    matrix_mul(paggr, canvas2p, canvas2pdev_matrix);
+}
+
+/*! \brief Compute area in parent cached coord for a cached coord.
+ *
+ * The coordination system of cached coord and descendants is resized,
+ * and shifted.  It makes all descendants bound by a box, canvas box,
+ * at 0, 0 and size is the same as the canvas.
+ *
+ * The bounding box where the canvas would be draw on the canvas on
+ * ancestral cached coord can be retreived by shifting and resizing
+ * canvas box in reverse and transform to coordination system of
+ * ancestral cached coord.
+ */ 
+static void compute_pcache_area(coord_t *coord) {
+    co_aix cached2pdev[6];
+    int c_w, c_h;
+    canvas_t *canvas;
+    coord_canvas_info_t *canvas_info;
+    co_aix poses[4][2];
+    
+    canvas_info = coord->canvas_info;
+    SWAP(canvas_info->pcache_cur_area, canvas_info->pcache_last_area,
+	 area_t *);
+    compute_cached_2_pdev_matrix(coord, cached2pdev);
+    
+    canvas = _coord_get_canvas(coord);
+    canvas_get_size(canvas, &c_w, &c_h);
+    
+    poses[0][0] = 0;
+    poses[0][1] = 0;
+    poses[1][0] = c_w;
+    poses[1][1] = c_h;
+    poses[2][0] = 0;
+    poses[2][1] = c_h;
+    poses[3][0] = c_w;
+    poses[3][1] = 0;
+    matrix_trans_pos(cached2pdev, &poses[0][0], &poses[0][1]);
+    matrix_trans_pos(cached2pdev, &poses[1][0], &poses[1][1]);
+    matrix_trans_pos(cached2pdev, &poses[2][0], &poses[2][1]);
+    matrix_trans_pos(cached2pdev, &poses[3][0], &poses[3][1]);
+    
+    area_init(coord_get_pcache_area(coord), 4, poses);
+
+    coord_set_flags(coord, COF_DIRTY_PCACHE_AREA);
+}
+
+/*! \brief Compute area of a coord.
+ */
+static int
+compute_area(coord_t *coord) {
     static co_aix (*poses)[2];
     static int max_poses = 0;
+    geo_t *geo;
     int cnt, pos_cnt;
     
-    /* Clean member shapes. */
     cnt = 0;
     FORMEMBERS(coord, geo) {
-	clean_shape(geo->shape);
 	cnt++;
     }
-
+    
     if(max_poses < (cnt * 2)) {
 	free(poses);
 	max_poses = cnt * 2;
@@ -1246,34 +1359,52 @@
 	    return ERR;
     }
 
-    /* Compute area of the coord. */
     pos_cnt = 0;
     FORMEMBERS(coord, geo) {
 	area_to_positions(geo->cur_area, poses + pos_cnt);
 	pos_cnt += 2;
     }
 
-    area_init(coord->cur_area, pos_cnt, poses);
+    area_init(coord_get_area(coord), pos_cnt, poses);
+
+    return OK;
+}
+
+static int coord_clean_members_n_compute_area(coord_t *coord) {
+    geo_t *geo;
+    int r;
+    /*! \note poses is shared by invokings, it is not support reentrying. */
     
+    /* Clean member shapes. */
+    FORMEMBERS(coord, geo) {
+	clean_shape(geo->shape);
+    }
+
+    r = compute_area(coord);
+    if(r != OK)
+	return ERR;
+
     return OK;
 }
 
 /*! \brief Clean dirty coords.
  *
+ * This function compute aggregation matrix and area for dirty
+ * coords. But, aggregation matrix of a cached coord is different from
+ * normal one. (see compute_aggr_of_cached_coord()).
+ *
  * \note coords their opacity != 1 are also traded as cached ones.
  */
 static int clean_coord(redraw_man_t *rdman, coord_t *coord) {
+    coord_t *child;
     int r;
     
     setup_canvas_info(rdman, coord);
 
-    if(coord->flags & COF_OWN_CANVAS)
-	compute_aggr_of_cached_coord(coord);
-    else
-	compute_aggr_of_coord(coord);
+    compute_aggr(coord);
 
     /* Areas of cached coords are computed in two phase.
-     * Phase 1 works like other normal ones.  Phase 2, is collect
+     * Phase 1 works like other normal ones.  Phase 2, collects
      * all areas of descendants to compute a minimum covering area.
      * Phase 2 is performed by zeroing_coord().
      */
@@ -1281,15 +1412,29 @@
     if(r != OK)
 	return ERR;
 
-    coord->flags &= ~COF_DIRTY;
+    add_dirty_area(rdman, coord, coord->cur_area);
+    add_dirty_area(rdman, coord, coord->last_area);
 
+    coord_clear_flags(coord, COF_DIRTY);
+    coord_set_flags(coord, COF_JUST_CLEAN);
+    
+    FORCHILDREN(coord, child) {
+	if(coord_is_cached(child))
+	    add_dirty_pcache_area_coord(rdman, child);
+    }
+    
     return OK;
 }
 
 /*! \brief Clean coord_t objects.
+ *
+ * It computes aggregation matrix and area for dirty coords.
+ *
+ * This function also responsible for computing area of parent cached
+ * coord, coord_canvas_info_t::pcache_cur_area, for its cached children.
  */
 static int clean_rdman_coords(redraw_man_t *rdman) {
-    coord_t *coord;
+    coord_t *coord, *child;
     coord_t **dirty_coords;
     int n_dirty_coords;
     int i, r;
@@ -1298,17 +1443,14 @@
     if(n_dirty_coords > 0) {
 	dirty_coords = rdman->dirty_coords.ds;
 	_insert_sort((void **)dirty_coords, n_dirty_coords,
-		     OFFSET(coord_t, order));
+		     OFFSET(coord_t, order)); /* ascend order */
 	for(i = 0; i < n_dirty_coords; i++) {
 	    coord = dirty_coords[i];
-	    if(!(coord->flags & COF_DIRTY))
+	    if(!coord_get_flags(coord, COF_DIRTY | COF_JUST_CLEAN))
 		continue;
 	    r = clean_coord(rdman, coord);
 	    if(r != OK)
 		return ERR;
-	    /* These two steps can be avoided for drawing all. */
-	    add_dirty_area(rdman, coord, &coord->areas[0]);
-	    add_dirty_area(rdman, coord, &coord->areas[1]);
 	}
     }
     return OK;
@@ -1347,7 +1489,8 @@
 static
 void zeroing_coord(redraw_man_t *rdman, coord_t *coord) {
     coord_t *cur;
-    area_t *area;
+    area_t *area, *saved_area;
+    geo_t *geo;
     co_aix min_x, min_y;
     co_aix max_x, max_y;
     co_aix x, y;
@@ -1355,7 +1498,7 @@
     int c_w, c_h;
     mbe_t *canvas;
     co_aix *aggr;
-    co_aix poses[2][2];
+    co_aix poses[4][2];
 
     if(coord->parent == NULL)	/*! \note Should not zeroing root coord */
 	abort();
@@ -1367,7 +1510,7 @@
     /*
      * Compute minimum overing area of sub-graphic
      */
-    area = &coord->canvas_info->owner_mems_area;
+    area = coord_get_area(coord);
     min_x = area->x;
     min_y = area->y;
     max_x = min_x + area->w;
@@ -1389,39 +1532,34 @@
 	    max_x = x;
 	if(y > max_y)
 	    max_y = y;
-	if(cur->flags & COF_OWN_CANVAS)
+	if(coord_is_cached(cur))
 	    preorder_coord_skip_subtree(cur);
     }
 
     w = max_x - min_x;
     h = max_y - min_y;
     
-    /*
-     * Setup area of the coord
-     */
-    aggr = coord_get_aggr_matrix(coord);
-    x = y = 0;
-    coord_trans_pos(coord->parent, &x, &y);
-    poses[0][0] = x;
-    poses[0][1] = y;
-    x = w;
-    y = h;
-    coord_trans_pos(coord->parent, &x, &y);
-    poses[1][0] = x;
-    poses[1][1] = y;
-
-    area_init(coord_get_area(coord), 2, poses);
-    
     canvas = _coord_get_canvas(coord);
     if(canvas)
 	canvas_get_size(canvas, &c_w, &c_h);
     else
 	c_w = c_h = 0;
-    
+
+    /* Without COF_JUST_CLEAN means the coordination system and matrix
+     * of the coord have not changed since last time of zeroing.  So,
+     * if canvas box cover all descendants, we don't need rezeroing,
+     * and avoid redraw all descendants.
+     *
+     * Width and height of actually drawing area should not be smaller
+     * than half of canvas's width and height.
+     */
     if(!coord_get_flags(coord, COF_JUST_CLEAN) &&
-       min_x >= 0 && min_y >= 0 && max_x <= c_w && max_y <= c_h)
+       min_x >= 0 && min_y >= 0 && max_x <= c_w && max_y <= c_h &&
+       h >= (c_h >> 2) && w >= (c_w >> 2)) {
 	/* Canvas fully cover sub-graphic. */
+	coord_set_flags(coord, COF_SKIP_ZERO);
 	return;
+    }
     
     /*
      * Adjust matrics of descendants to align left-top corner of
@@ -1429,25 +1567,32 @@
      * zeroing coord.
      */
     FOR_COORDS_PREORDER(coord, cur) {
+	if(coord_is_cached(cur) && coord != cur) {
+	    /*
+	     * Cached coords are zeroed from root to leaves, so
+	     * changes of aggr_matrix would be propagated to next
+	     * level of cached.
+	     */
+	    preorder_coord_skip_subtree(cur);
+	}
+	/* Shift space */
 	aggr = coord_get_aggr_matrix(cur);
 	aggr[3] -= min_x;
 	aggr[5] -= min_y;
-	if(coord_get_flags(cur, COF_OWN_CANVAS)) {
-	    /*
-	     * Coords, zeroing, is zeroed in preorder of tree.
-	     * So, they are zeroed after ancesters with correctly
-	     * coord_t::aggr_matrix of parent coord to zeroing.
-	     */
-	    preorder_coord_skip_subtree(cur);
-	    area = coord_get_area(cur);
-	    area->x -= min_x;
-	    area->y -= min_y;
-	} else
-	    coord_clean_members_n_compute_area(cur);
+	
+	FOR_COORD_MEMBERS(coord, geo) {
+	    /* \see GEO_SWAP() */
+	    if(!geo_get_flags(geo, GEF_SWAP))
+		SWAP(geo->cur_area, geo->last_area, area_t *);
+	}
+	coord_clean_members_n_compute_area(cur);
     }
     
     /*
      * Setup canvas
+     *
+     * Canvas of a cached coord is not setted in
+     * coord_canvas_info_new().  It should be setted, here.
      */
     if(canvas == NULL || w > c_w || h > c_w) {
 	if(canvas)
@@ -1456,16 +1601,10 @@
 	_coord_set_canvas(coord, canvas);
     }
 
-    area = &coord->canvas_info->cached_dirty_area;
-    area->x = 0;
-    area->y = 0;
-    area->w = w;
-    area->h = h;
-    DARRAY_CLEAN(_coord_get_dirty_areas(coord));
-    add_dirty_area(rdman, coord, area);
+    coord_set_flags(coord, COF_JUST_ZERO);
 }
 
-/*! \brief Add canvas owner of dirty geos to coord_t::zeroing_coords.
+/*! \brief Add canvas owner of dirty geos to redraw_man_t::zeroing_coords.
  *
  * All possible coords that need a zeroing have at least one dirty geo.
  */
@@ -1476,37 +1615,46 @@
     int n_dirty_coords;
     coord_t **dirty_coords, *coord;
 
+    /* Mark all cached ancestral coords of dirty geos */
     n_dirty_geos = rdman->dirty_geos.num;
     dirty_geos = rdman->dirty_geos.ds;
     for(i = 0; i < n_dirty_geos; i++) {
 	geo = dirty_geos[i];
-	coord = geo_get_coord(geo)->canvas_info->owner;
+	coord = coord_get_cached(geo_get_coord(geo));
 	while(!coord_get_flags(coord, COF_MUST_ZEROING | COF_TEMP_MARK)) {
-	    coord_set_flags(coord, COF_TEMP_MARK);
 	    if(coord_is_root(coord))
 		break;
-	    coord = coord->parent->canvas_info->owner;
+	    coord_set_flags(coord, COF_TEMP_MARK);
+	    coord = coord_get_cached(coord_get_parent(coord));
 	}
     }
     
+    /* Mark all cached ancestral coords of dirty coords */
     n_dirty_coords = rdman->dirty_coords.num;
     dirty_coords = rdman->dirty_coords.ds;
     for(i = 0; i < n_dirty_coords; i++) {
-	coord = dirty_coords[i]->canvas_info->owner;
+	coord = coord_get_cached(dirty_coords[i]);
 	while(!coord_get_flags(coord, COF_MUST_ZEROING | COF_TEMP_MARK)) {
-	    coord_set_flags(coord, COF_TEMP_MARK);
 	    if(coord_is_root(coord))
 		break;
-	    coord = coord->parent->canvas_info->owner;
+	    coord_set_flags(coord, COF_TEMP_MARK);
+	    coord = coord_get_cached(coord_get_parent(coord));
 	}
     }
     
+    /* Add all marked coords into redraw_man_t::zeroing_coords list */
     FOR_COORDS_PREORDER(rdman->root_coord, coord) {
+	if(!coord_is_cached(coord))
+	    continue;		/* skip coords that is not cached */
+	
 	if(!coord_get_flags(coord, COF_TEMP_MARK)) {
+	    if(coord_get_flags(coord, COF_DIRTY_PCACHE_AREA))
+		add_dirty_pcache_area_coord(rdman, coord);
 	    preorder_coord_skip_subtree(coord);
 	    continue;
 	}
 	add_zeroing_coord(rdman, coord);
+	
 	coord_clear_flags(coord, COF_TEMP_MARK);
     }
     
@@ -1515,7 +1663,9 @@
 
 /*! \brief Zeroing coords in redraw_man_t::zeroing_coords.
  *
- * \note redraw_man_t::zeroing_coords must in ascent partial order of tree.
+ * \note redraw_man_t::zeroing_coords must in descent partial order of
+ *	 tree.  The size of a cached coord is effected by cached
+ *	 descendants.
  */
 static int zeroing_rdman_coords(redraw_man_t *rdman) {
     int i;
@@ -1523,45 +1673,48 @@
     coord_t *coord;
    
     all_zeroing = &rdman->zeroing_coords;
+    /*! Zeroing is performed from leaves to root.
+     *
+     * REASON: The size of canvas is also effected by cached
+     *         descedants.  A cached coord is only effected by parent
+     *         cached coord when it-self is dirty.  When a cached
+     *         coord is dirty, it is clean (compute aggregated matrix)
+     *         by recomputing a scale for x and y-axis from aggregated
+     *         matrix of parent coord.  And, cleaning coord is
+     *         performed before zeroing.  It means ancestors of a
+     *         cached coord would not effect it when zeroing.
+     */
     for(i = all_zeroing->num - 1; i >= 0; i--) {
 	coord = all_zeroing->ds[i];
-	if(coord_is_root(coord))
-	    continue;
 	zeroing_coord(rdman, coord);
+	compute_pcache_area(coord);
     }
-
+    
     return OK;
 }
 
-/* \brief Compute matrix from cached canvas to parent device space.
+/*! \brief Compute pcache_area for coords whoes pcache_area is dirty.
+ *
+ * coord_t::dirty_pcache_area_coords also includes part of coords in
+ * coord_t::zeroing_coords.  The pcache_area of coords that is in
+ * coord_t::dirty_pcache_area_coords, but is not in
+ * coord_t::zeroing_coords should be computed here.
+ * zeroing_rdman_coords() is responsible for computing pcache_area for
+ * zeroing ones.
  */
-static void compute_cached_2_pdev_matrix(coord_t *coord,
-					   co_aix canvas2pdev_matrix[6]) {
-    coord_t *parent;
-    co_aix *aggr;
-    co_aix *matrix, *paggr;
-    co_aix scale_x, scale_y;
-    co_aix shift_x, shift_y;
-    co_aix canvas2p[6];
-
-    aggr = coord_get_aggr_matrix(coord);
-    matrix = coord->matrix;
-    parent = coord->parent;
-    paggr = coord_get_aggr_matrix(parent);
+static int
+compute_rdman_coords_pcache_area(redraw_man_t *rdman) {
+    coords_t *all_coords;
+    coord_t *coord;
+    int i;
     
-    scale_x = matrix[0] / aggr[0];
-    scale_y = matrix[3] / aggr[3];
-    shift_x = matrix[2] - scale_x * aggr[2];
-    shift_y = matrix[5] - scale_y * aggr[5];
-
-    canvas2p[0] = scale_x;
-    canvas2p[1] = 0;
-    canvas2p[2] = shift_x;
-    canvas2p[3] = 0;
-    canvas2p[4] = scale_y;
-    canvas2p[5] = shift_y;
-
-    matrix_mul(paggr, canvas2p, canvas2pdev_matrix);
+    all_coords = &rdman->dirty_pcache_area_coords;
+    for(i = 0; i < all_coords->num; i++) {
+	coord = all_coords->ds[i];
+	if(coord_get_flags(coord, COF_DIRTY_PCACHE_AREA))
+	    compute_pcache_area(coord);
+    }
+    return OK;
 }
 
 /*! \brief Add aggregated dirty areas to ancestor.
@@ -1574,6 +1727,7 @@
 					      coord_t *coord) {
     int i;
     int n_areas;
+    int enable_poses1 = 0;
     co_aix poses0[2][2], poses1[2][2];
     co_aix reverse[6];
     co_aix canvas2pdev_matrix[6];
@@ -1586,27 +1740,27 @@
     if(n_areas == 0)
 	abort();		/* should not happen! */
     
-    area0 = coord->canvas_info->aggr_dirty_areas;
+    area0 = _coord_get_aggr_dirty_areas(coord);
     area1 = area0 + 1;
 
+    /* TODO: Since both cur & last area of coords are added into dirty
+     *       area list, position of both areas shoud be adjusted for
+     *       all descendants when zeroing a cached coord.
+     */
     for(i = 0; i < n_areas; i++) {
 	area = areas[i];
 	if(area->w != 0 || area->h != 0)
 	    break;
     }
 
-    if(i < n_areas) {
-	area = areas[i++];
-	poses0[0][0] = area->x;
-	poses0[0][1] = area->y;
-	poses0[1][0] = area->x + area->w;
-	poses0[1][1] = area->y + area->h;
-    } else {
-	poses0[0][0] = 0;
-	poses0[0][1] = 0;
-	poses0[1][0] = 0;
-	poses0[1][1] = 0;
-    }
+    if(i >= n_areas)
+	return;
+    
+    area = areas[i++];
+    poses0[0][0] = area->x;
+    poses0[0][1] = area->y;
+    poses0[1][0] = area->x + area->w;
+    poses0[1][1] = area->y + area->h;
     
     if(i < n_areas) {
 	area = areas[i++];
@@ -1620,7 +1774,7 @@
 	poses1[1][0] = 0;
 	poses1[1][1] = 0;
     }
-	
+    
     for(; i < n_areas - 1;) {
 	/* Even areas */
 	area = areas[i++];
@@ -1639,7 +1793,7 @@
 	    poses1[1][1] = MB_MAX(poses1[1][1], area->y + area->h);
 	}
     }
-
+    
     if(i < n_areas) {
 	area = areas[i];
 	if(area->w != 0 || area->h != 0) {
@@ -1649,110 +1803,206 @@
 	    poses0[1][1] = MB_MAX(poses0[1][1], area->y + area->h);
 	}
     }
-
-    parent = coord->parent;
-    pcached_coord = parent->canvas_info->owner;
+    
+    parent = coord_get_parent(coord);
+    pcached_coord = coord_get_cached(parent);
     
     compute_cached_2_pdev_matrix(coord, canvas2pdev_matrix);
-    
+
+    /* Add dirty areas to parent cached coord. */
     matrix_trans_pos(canvas2pdev_matrix, poses0[0], poses0[0] + 1);
     matrix_trans_pos(canvas2pdev_matrix, poses0[1], poses0[1] + 1);
     area_init(area0, 2, poses0);
     add_dirty_area(rdman, pcached_coord, area0);
-
+    
     matrix_trans_pos(canvas2pdev_matrix, poses1[0], poses1[0] + 1);
     matrix_trans_pos(canvas2pdev_matrix, poses1[1], poses1[1] + 1);
     area_init(area1, 2, poses1);
-    if(area1->w != 0 || area1->h != 0)
-	if(area0->x != area1->x || area0->y != area1->y ||
-	   area0->w != area1->w || area0->h != area1->h)
-	    add_dirty_area(rdman, pcached_coord, area1);
+    add_dirty_area(rdman, pcached_coord, area1);
 
     if(coord_get_flags(coord, COF_JUST_CLEAN) &&
        !coord_get_flags(pcached_coord, COF_JUST_CLEAN))
 	add_dirty_area(rdman, pcached_coord, coord->last_area);
 }
 
+/*! \brief To test if redrawing all elements on the canvas of a cached coord.
+ */
+#define IS_CACHE_REDRAW_ALL(co)					\
+    (coord_get_flags((co), COF_JUST_CLEAN | COF_JUST_ZERO))
+
+/* Aggregate dirty areas and propagate them to ancestor cached coord.
+ *
+ * The aggregation is performed from leaves to root.  But, this
+ * function do not aggregate dirty areas for root coord.  The dirty
+ * areas of a cached coord are aggregated into two areas, one for old
+ * areas and one or new areas.  Both aggregation areas are add into
+ * dirty_areas list of closet ancestral cached coord.
+ */
 static int add_rdman_aggr_dirty_areas(redraw_man_t *rdman) {
     int i;
     int n_zeroing;
     coord_t **zeroings;
-    coord_t *coord;
+    coord_t *coord, *pcached_coord;
+    int n_dpca_coords;		/* number of dirty pcache area coords */
+    coord_t **dpca_coords;	/* dirty pcache area coords */
     
+    /* Add aggregated areas to parent cached one for coords in zeroing
+     * list
+     */
     n_zeroing = rdman->zeroing_coords.num;
     zeroings = rdman->zeroing_coords.ds;
-    for(i = n_zeroing - 1; i >= 0; i--) {
+    for(i = 0; i < n_zeroing; i++) {
+	if(coord_get_flags(coord, COF_TEMP_MARK))
+	    continue;
+	coord_set_flags(coord, COF_TEMP_MARK);
+	
 	coord = zeroings[i];
-	if(!coord_is_root(coord))
+	pcached_coord = coord_get_cached(coord_get_parent(coord));
+	
+	if(coord_is_root(coord) || IS_CACHE_REDRAW_ALL(pcached_coord))
+	    continue;
+	
+	if(IS_CACHE_REDRAW_ALL(coord)) {
+	    add_dirty_area(rdman, pcached_coord,
+			   coord_get_pcache_area(coord));
+	    add_dirty_area(rdman, pcached_coord,
+			   coord_get_pcache_last_area(coord));
+	} else {
 	    add_aggr_dirty_areas_to_ancestor(rdman, coord);
+	}
+    }
+    
+    /* Add pcache_areas to parent cached one for coord that is
+     * non-zeroing and its parent is changed.
+     */
+    n_dpca_coords = rdman->dirty_pcache_area_coords.num;
+    dpca_coords = rdman->dirty_pcache_area_coords.ds;
+    for(i = 0; i < n_dpca_coords; i++) {
+	if(coord_get_flags(coord, COF_TEMP_MARK))
+	    continue;
+	coord_set_flags(coord, COF_TEMP_MARK);
+
+	coord = dpca_coords[i];
+	pcached_coord = coord_get_cached(coord_get_parent(coord));
+	
+	if(coord_is_root(coord) || IS_CACHE_REDRAW_ALL(pcached_coord))
+	    continue;
+	
+	add_dirty_area(rdman, pcached_coord,
+		       coord_get_pcache_area(coord));
+	add_dirty_area(rdman, pcached_coord,
+		       coord_get_pcache_last_area(coord));
     }
 
-    return OK;
-}
-
-static int add_rdman_cached_dirty_areas(redraw_man_t *rdman) {
-    int i;
-    coord_t *coord, **dirty_coords;
-    int n_dirty_coords;
-
-    n_dirty_coords = rdman->dirty_coords.num;
-    dirty_coords = rdman->dirty_coords.ds;
-    for(i = 0; i < n_dirty_coords; i++) {
-	coord = dirty_coords[i];
-	if(coord_get_flags(coord, COF_OWN_CANVAS)) {
-	    add_dirty_area(rdman, coord, coord->cur_area);
-	    add_dirty_area(rdman, coord, coord->last_area);
-	}
+    /* Remove temporary mark */
+    for(i = 0; i < n_zeroing; i++) {
+	coord_clear_flags(zeroings[i], COF_TEMP_MARK);
+    }
+    for(i = 0; i < n_dpca_coords; i++) {
+	coord_clear_flags(dpca_coords[i], COF_TEMP_MARK);
     }
 
     return OK;
 }
 
-static int clean_rdman_dirties(redraw_man_t *rdman) {
+/*! \brief Swap geo_t::cur_area and geo_t::last_area for a geo_t.
+ *
+ * It is call by rdman_clean_dirties() to swap areas for members of
+ * dirty coord in redraw_man_t::dirty_coords and dirty geos in
+ * redraw_man_t::dirty_geos.
+ *
+ * zeroing_coord() would also swap some areas for members of
+ * descendants of a cached coord.  But, only members that was not
+ * swapped, without GEF_SWAP flag, in this round of redrawing.
+ * zeroing_coord() would not mark geos with GEF_SWAP since it not not
+ * referenced later.  We don't mark geos in zeroing_coord() because we
+ * don't want to unmark it later.  To unmark it, we should re-travel
+ * forest of cached coords in redraw_man_t::zeroing_coords.  It is
+ * expansive.
+ */
+#define GEO_SWAP(g)					\
+    if(!geo_get_flags((g), GEF_SWAP)) {			\
+	SWAP((g)->cur_area, (g)->last_area, area_t *);	\
+	geo_set_flags((g), GEF_SWAP);			\
+    }
+
+/* \brief Clean dirty coords and shapes.
+ *
+ * The procedure of clean dirty coords and shapes include 3 major steps.
+ *
+ *   - Add dirty coords and shapes to rdman.
+ *     - All descendants of a dirty coord are also dirty, except
+ *       descendants of cached descendants.
+ *   - Recompute aggregated transformation matrix from root to leaves
+ *     for dirty coords.
+ *     - The aggregated transformation matrix for a cached coord is
+ *       different from other coords.
+ *   - Compute new area for every dirty coord.
+ *     - Area of a dirty coord is an aggregation of areas of all members.
+ *     - A cached coord has two type of areas, one is for members of the cached
+ *       coord, another one is for the block that cached coord and descendants
+ *       will be mapped in parent cached coord.
+ *       - Areas, for parent cached coord (pcache_cur_area), of
+ *         non-dirty cached coord would be recomputed when cleaning
+ *         parent coord.
+ *       - Areas, for parent cached coord (pcache_cur_area), of dirty
+ *         cached coord would be recomputed when zeroing the cached
+ *         coord. (because zeroing would change aggregated matrix, and
+ *         zeroing was performed after cleaning)
+ *       - Areas, for members, of dirty cached coord would only be
+ *         recomputed when cleaning the coord.
+ *   - Perform zeroing on some cached coords that
+ *     - dirty, is,
+ *     - dirty descendants, has.
+ *   - Propagate dirty areas to dirty area list of parent cached coord
+ *     for every cached coords, not only for dirty cached coords.
+ *
+ * The cur_area of a cached coord is where members of the coord will
+ * be draw in cache buffer, i.e. surface.  The area of the cached
+ * coord and descendants is described by pcache_cur_area and
+ * pcache_last_area in coord_canvas_info_t.
+ */
+static int rdman_clean_dirties(redraw_man_t *rdman) {
     int r;
     int i;
     coord_t **coords, *coord;
     geo_t **geos;
+    geo_t *geo;
 
     /* coord_t::cur_area of coords are temporary pointed to
      * coord_canvas_info_t::owner_mems_area for store area
-     * by clean_coor().
+     * by clean_coord().
      */
     coords = rdman->dirty_coords.ds;
     for(i = 0; i < rdman->dirty_coords.num; i++) {
 	coord = coords[i];
-	if(coord->flags & COF_DIRTY) {
-	    if(!coord_get_flags(coord, COF_OWN_CANVAS))
-		SWAP(coord->cur_area, coord->last_area, area_t *);
-	    else {
-		coord->last_area = coord->cur_area;
-		coord->cur_area = &coord->canvas_info->owner_mems_area;
-	    }
+	SWAP(coord->cur_area, coord->last_area, area_t *);
+	FOR_COORD_MEMBERS(coord, geo) {
+	    GEO_SWAP(geo);
 	}
     }
     
     geos = rdman->dirty_geos.ds;
-    for(i = 0; i < rdman->dirty_geos.num; i++)
-	if(geos[i]->flags & GEF_DIRTY)
-	    SWAP(geos[i]->cur_area, geos[i]->last_area, area_t *);
-
+    for(i = 0; i < rdman->dirty_geos.num; i++) {
+	geo = geos[i];
+	GEO_SWAP(geo);
+    }
+    
     r = clean_rdman_coords(rdman);
     if(r != OK)
 	return ERR;
-    
-    coords = rdman->dirty_coords.ds;
-    for(i = 0; i < rdman->dirty_coords.num; i++) {
-	coord = coords[i];
-	coord_set_flags(coord, COF_JUST_CLEAN);
-	coord->cur_area =
-	    (coord->last_area == coord->areas)?
-	    coord->areas + 1: coord->areas;
-    }
+
+    /* TODO: save area of cached coord and descendants in
+     *       cached_dirty_area for parent cached coord space.
+     */
 
     r = clean_rdman_geos(rdman);
     if(r != OK)
 	return ERR;
 
+    /* Zeroing must be performed after clearing to get latest position
+     * of shapes for computing new bounding box
+     */
     r = add_rdman_zeroing_coords(rdman);
     if(r != OK)
 	return ERR;
@@ -1761,17 +2011,40 @@
     if(r != OK)
 	return ERR;
 
+    r = compute_rdman_coords_pcache_area(rdman);
+    if(r != OK)
+	return ERR;
+    
     r = add_rdman_aggr_dirty_areas(rdman);
     if(r != OK)
 	return ERR;
 
-    r = add_rdman_cached_dirty_areas(rdman);
-    if(r != OK)
-	return ERR;
-
+    /*
+     * Clear all flags setted by zeroing.
+     */
     coords = rdman->dirty_coords.ds;
-    for(i = 0; i < rdman->dirty_coords.num; i++)
-	coord_clear_flags(coords[i], COF_JUST_CLEAN);
+    for(i = 0; i < rdman->dirty_coords.num; i++) {
+	coord = coords[i];
+	coord_clear_flags(coord, COF_JUST_CLEAN);
+	/* \see GEO_SWAP() */
+	FOR_COORD_MEMBERS(coord, geo) {
+	    geo_clear_flags(geo, GEF_SWAP);
+	}
+    }
+    coords = rdman->zeroing_coords.ds;
+    for(i = 0; i < rdman->zeroing_coords.num; i++)
+	coord_clear_flags(coords[i],
+			  COF_JUST_CLEAN | COF_JUST_ZERO | COF_SKIP_ZERO);
+    coords = rdman->dirty_pcache_area_coords.ds;
+    for(i = 0; i < rdman->dirty_pcache_area_coords.num; i++)
+	coord_clear_flags(coords[i],
+			  COF_JUST_CLEAN | COF_JUST_ZERO | COF_SKIP_ZERO);
+    
+    /* \see GEO_SWAP() */
+    for(i = 0; i < rdman->dirty_geos.num; i++) {
+	geo = geos[i];
+	geo_clear_flags(geo, GEF_SWAP);
+    }
     
     return OK;
 }
@@ -1865,12 +2138,7 @@
 
 #ifndef UNITTEST
 static void clear_canvas(canvas_t *canvas) {
-    mbe_operator_t old_op;
-
-    old_op = mbe_get_operator(canvas);
-    mbe_set_operator(canvas, MBE_OPERATOR_CLEAR);
-    mbe_paint(canvas);
-    mbe_set_operator(canvas, old_op);
+    mbe_clear(canvas);
 }
 
 static void make_clip(mbe_t *cr, int n_dirty_areas,
@@ -1881,6 +2149,8 @@
     mbe_new_path(cr);
     for(i = 0; i < n_dirty_areas; i++) {
 	area = dirty_areas[i];
+	if(area->w < 0.1 || area->h < 0.1)
+	    continue;
 	mbe_rectangle(cr, area->x, area->y, area->w, area->h);
     }
     mbe_clip(cr);
@@ -1892,15 +2162,10 @@
 
 static void copy_cr_2_backend(redraw_man_t *rdman, int n_dirty_areas,
 			      area_t **dirty_areas) {
-    mbe_operator_t saved_op;
-    
     if(n_dirty_areas)
 	make_clip(rdman->backend, n_dirty_areas, dirty_areas);
     
-    saved_op = mbe_get_operator(rdman->backend);
-    mbe_set_operator(rdman->backend, MBE_OPERATOR_SOURCE);
-    mbe_paint(rdman->backend);
-    mbe_set_operator(rdman->backend, saved_op);
+    mbe_copy_source(rdman->cr, rdman->backend);
 }
 #else /* UNITTEST */
 static void make_clip(mbe_t *cr, int n_dirty_areas,
@@ -1923,7 +2188,6 @@
     mbe_t *pcanvas, *canvas;
     mbe_surface_t *surface;
     mbe_pattern_t *pattern;
-    mbe_matrix_t cr_matrix;
     co_aix reverse[6];
     co_aix canvas2pdev_matrix[6];
 
@@ -1933,18 +2197,11 @@
     compute_cached_2_pdev_matrix(coord, canvas2pdev_matrix);
     compute_reverse(canvas2pdev_matrix, reverse);
     
-    cr_matrix.xx = reverse[0];
-    cr_matrix.xy = reverse[1];
-    cr_matrix.x0 = reverse[2];
-    cr_matrix.yx = reverse[3];
-    cr_matrix.yy = reverse[4];
-    cr_matrix.y0 = reverse[5];
-
     canvas = _coord_get_canvas(coord);
     pcanvas = _coord_get_canvas(coord->parent);
     surface = mbe_get_target(canvas);
     pattern = mbe_pattern_create_for_surface(surface);
-    mbe_pattern_set_matrix(pattern, &cr_matrix);
+    mbe_pattern_set_matrix(pattern, reverse);
     mbe_set_source(pcanvas, pattern);
     mbe_paint_with_alpha(pcanvas, coord->opacity);
 }
@@ -1972,7 +2229,7 @@
     child = FIRST_CHILD(coord);
     while(child != NULL || member != NULL) {
 	if(child && child->before_pmem == mem_idx) {
-	    if(child->flags & COF_OWN_CANVAS) {
+	    if(coord_is_cached(child)) {
 		if(!(child->flags & COF_HIDDEN) &&
 		   is_area_in_areas(coord_get_area(child), n_areas, areas)) {
 		    update_cached_canvas_2_parent(rdman, child);
@@ -2002,11 +2259,28 @@
 static int draw_dirty_cached_coord(redraw_man_t *rdman,
 				   coord_t *coord) {
     area_t **areas, *area;
+    area_t full_area;
     int n_areas;
     mbe_t *canvas;
+    mbe_surface_t *surface;
     int i;
     int r;
     
+    canvas = _coord_get_canvas(coord);
+    
+    if(IS_CACHE_REDRAW_ALL(coord)) {
+	/*
+	 * full_area covers all dirty areas of the cached coord.
+	 */
+	DARRAY_CLEAN(_coord_get_dirty_areas(coord));
+	surface = mbe_get_target(canvas);
+	full_area.x = 0;
+	full_area.y = 0;
+	full_area.w = mbe_image_surface_get_width(surface);
+	full_area.h = mbe_image_surface_get_height(surface);
+	add_dirty_area(rdman, coord, &full_area);
+    }
+
     areas = _coord_get_dirty_areas(coord)->ds;
     n_areas = _coord_get_dirty_areas(coord)->num;
     
@@ -2018,7 +2292,6 @@
 	area->h = ceilf(area->h);
     }
 
-    canvas = _coord_get_canvas(coord);
     make_clip(canvas, n_areas, areas);
     clear_canvas(canvas);
 
@@ -2030,13 +2303,27 @@
 }
 
 static void draw_shapes_in_dirty_areas(redraw_man_t *rdman) {
+    int num;
+    coord_t **zeroings;
+    coord_t *coord;
     int i;
-    coord_t *coord;
 
-    for(i = rdman->zeroing_coords.num - 1; i >= 0; i--) {
-	coord = rdman->zeroing_coords.ds[i];
+    zeroings = rdman->zeroing_coords.ds;
+    num = rdman->zeroing_coords.num;
+    /* Draw cached ones from leaves to root.
+     * Since content of cached ones depend on descendants.
+     */
+    for(i = num - 1; i >= 0; i--) {
+	coord = zeroings[i];
+	if(coord_get_flags(coord, COF_TEMP_MARK))
+	    continue;
 	draw_dirty_cached_coord(rdman, coord);
+	coord_set_flags(coord, COF_TEMP_MARK);
     }
+    for(i = 0; i < num; i++)
+	coord_clear_flags(coord, COF_TEMP_MARK);
+
+    draw_dirty_cached_coord(rdman, rdman->root_coord);
 }
 
 
@@ -2081,7 +2368,7 @@
     int n_areas;
     area_t **areas;
     
-    r = clean_rdman_dirties(rdman);
+    r = rdman_clean_dirties(rdman);
     if(r != OK)
 	return ERR;
 
@@ -2098,18 +2385,14 @@
 	    coord = rdman->zeroing_coords.ds[i];
 	    DARRAY_CLEAN(_coord_get_dirty_areas(coord));
 	}
+	DARRAY_CLEAN(_coord_get_dirty_areas(rdman->root_coord));
 	rdman->n_dirty_areas = 0;
     }
 
-    coords = rdman->zeroing_coords.ds;
-    for(i = 0; i < rdman->zeroing_coords.num; i++) {
-	coord = coords[i];
-	coord_clear_flags(coord, COF_MUST_ZEROING);
-    }
-
     DARRAY_CLEAN(&rdman->dirty_coords);
     DARRAY_CLEAN(&rdman->dirty_geos);
     DARRAY_CLEAN(&rdman->zeroing_coords);
+    DARRAY_CLEAN(&rdman->dirty_pcache_area_coords);
     
     /* Free postponsed removing */
     free_free_objs(rdman);
@@ -2196,7 +2479,7 @@
 int rdman_force_clean(redraw_man_t *rdman) {
     int r;
 
-    r = clean_rdman_dirties(rdman);
+    r = rdman_clean_dirties(rdman);
 
     return r;
 }
--- a/src/shape_image.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/shape_image.c	Wed Jun 09 17:30:09 2010 +0800
@@ -104,7 +104,6 @@
     co_aix img_matrix[6];
     co_aix x_factor, y_factor;
     int img_w, img_h;
-    mbe_matrix_t cmatrix;
     int i;
     
     poses = img->poses;
@@ -158,7 +157,6 @@
 void sh_image_draw(shape_t *shape, mbe_t *cr) {
     sh_image_t *img = (sh_image_t *)shape;
     mbe_pattern_t *saved_source;
-    mbe_matrix_t matrix, saved_matrix;
     co_aix *aggr;
     
     mbe_move_to(cr, img->poses[0][0], img->poses[0][1]);
--- a/src/shape_path.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/shape_path.c	Wed Jun 09 17:30:09 2010 +0800
@@ -385,9 +385,9 @@
  *
  * \todo Notify programmers that syntax or value error of path data.
  */
-static int sh_path_cmd_arg_cnt(char *data, int *cmd_cntp, int *pnt_cntp,
+static int sh_path_cmd_arg_cnt(const char *data, int *cmd_cntp, int *pnt_cntp,
 			       int *float_arg_cntp) {
-    char *p, *old;
+    const char *p, *old;
     int cmd_cnt, pnt_cnt, float_arg_cnt;
     int i;
 
@@ -564,8 +564,8 @@
 #define TO_ABSX islower(cmd)? x + atof(old): atof(old)
 #define TO_ABSY islower(cmd)? y + atof(old): atof(old)
 
-static int sh_path_cmd_arg_fill(char *data, sh_path_t *path) {
-    char *p, *old;
+static int sh_path_cmd_arg_fill(const char *data, sh_path_t *path) {
+    const char *p, *old;
     char *cmds;
     char cmd;
     co_aix *pnts;
@@ -738,7 +738,7 @@
 
 /*! \brief Create a path from value of 'data' of SVG path.
  */
-shape_t *rdman_shape_path_new(redraw_man_t *rdman, char *data) {
+shape_t *rdman_shape_path_new(redraw_man_t *rdman, const char *data) {
     sh_path_t *path;
     int cmd_cnt, pnt_cnt, float_arg_cnt;
     int msz;
--- a/src/shape_stext.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/shape_stext.c	Wed Jun 09 17:30:09 2010 +0800
@@ -1,7 +1,6 @@
 #include <stdio.h>
+#include <string.h>
 #include "mb_graph_engine.h"
-#include <cairo-ft.h>
-#include <fontconfig/fontconfig.h>
 #include "mb_shapes.h"
 #include "mb_tools.h"
 
@@ -59,8 +58,6 @@
 	move_xys[move_cnt][0] = x;		\
 	move_xys[move_cnt++][1] = y;		\
     } while(0)
-#undef mbe_show_text
-#define mbe_show_text(cr, txt)
 #undef mbe_scaled_font_destroy
 #define mbe_scaled_font_destroy(scaled)
 #undef mbe_text_path
@@ -128,106 +125,16 @@
 #define MBE_SET_WIDTH(ext, v) do { ((ext)->width) = v; } while(0)
 #define MBE_SET_HEIGHT(ext, v) do { ((ext)->height) = v; } while(0)
 
-/*! \brief Find out a font pattern.
- *
- * This function use fontconfig to decide a font file in pattern.  It can
- * replaced by other mechanism if you think it is not what you want.
- *
- * \param slant make font prune if it it non-zero.
- * \param weight make font normal if it is 100.
- */
-static
-FcPattern *query_font_pattern(const char *family, int slant, int weight) {
-    FcPattern *ptn, *p, *fn_ptn;
-    FcValue val;
-    FcConfig *cfg;
-    FcBool r;
-    FcResult result;
-    static int slant_map[] = {	/* from MB_FONT_SLANT_* to FC_SLANT_* */
-	FC_SLANT_ROMAN,
-	FC_SLANT_ROMAN,
-	FC_SLANT_ITALIC,
-	FC_SLANT_OBLIQUE};
-
-    cfg = FcConfigGetCurrent();
-    ptn = FcPatternCreate();
-    p = FcPatternCreate();
-    if(ptn == NULL || p == NULL)
-	goto err;
-
-    val.type = FcTypeString;
-    val.u.s = family;
-    FcPatternAdd(ptn, "family", val, FcTrue);
-    
-    val.type = FcTypeInteger;
-    val.u.i = slant_map[slant];
-    FcPatternAdd(ptn, "slant", val, FcTrue);
-    
-    val.type = FcTypeInteger;
-    val.u.i = weight;
-    FcPatternAdd(ptn, "weight", val, FcTrue);
-
-    r = FcConfigSubstituteWithPat(cfg, ptn, NULL, FcMatchPattern);
-    if(!r)
-	goto err;
-    
-    r = FcConfigSubstituteWithPat(cfg, p, ptn, FcMatchFont);
-    if(!r)
-	goto err;
-
-    FcDefaultSubstitute(p);
-
-    fn_ptn = FcFontMatch(cfg, p, &result);
-
-    /* It is supposed to return FcResultMatch.  But, it is no, now.
-     * I don't know why.  Someone should figure out the issue.
-     */
-#if 0
-    if(result != FcResultMatch) {
-	printf("%d %d\n", result, FcResultMatch);
-	goto err;
-    }
-#endif
-    if(fn_ptn == NULL)
-	goto err;
-
-    FcPatternDestroy(ptn);
-    FcPatternDestroy(p);
-    
-    return fn_ptn;
-    
-err:
-    if(ptn)
-	FcPatternDestroy(ptn);
-    if(p)
-	FcPatternDestroy(p);
-    return NULL;
-
+static mb_font_face_t *
+query_font_face(const char *family, int slant, int weight) {
+    return (mb_font_face_t *)mbe_query_font_face(family, slant, weight);
 }
 
-/*! \brief Find out a font face for a pattern specified.
- *
- * The pattern, here, is a vector of family, slant, and weight.
- * This function base on fontconfig and cairo FreeType font supporting.
- * You can replace this function with other font mechanisms.
- */
-static
-mb_font_face_t *query_font_face(const char *family, int slant, int weight) {
-    mbe_font_face_t *cface;
-    FcPattern *ptn;
-    
-    ptn = query_font_pattern(family, slant, weight);
-    cface = mbe_ft_font_face_create_for_pattern(ptn);
-    FcPatternDestroy(ptn);
-    
-    return (mb_font_face_t *)cface;
-}
-
-static
-void free_font_face(mb_font_face_t *face) {
+static void
+free_font_face(mb_font_face_t *face) {
     ASSERT(face == NULL);
 
-    mbe_font_face_destroy((mbe_font_face_t *)face);
+    mbe_free_font_face((mbe_font_face_t *)face);
 }
 
 /*! \brief This is scaled font for specified size and extent.
@@ -242,31 +149,13 @@
 mb_scaled_font_t *make_scaled_font_face_matrix(mb_font_face_t *face,
 					       co_aix *matrix) {
     mbe_scaled_font_t *scaled_font;
-    mbe_matrix_t font_matrix;
-    static mbe_matrix_t id = {
-	1, 0,
-	0, 1,
-	0, 0
-    };
-    static mbe_font_options_t *opt = NULL;
+    static co_aix id[6] = { 1, 0, 0,
+			    0, 1, 0 };
     
     ASSERT(matrix != NULL);
     
-    if(opt == NULL) {
-	opt = mbe_font_options_create();
-	if(opt == NULL)
-	    return NULL;
-    }
-
-    font_matrix.xx = *matrix++;
-    font_matrix.xy = *matrix++;
-    font_matrix.x0 = *matrix++;
-    font_matrix.yx = *matrix++;
-    font_matrix.yy = *matrix++;
-    font_matrix.y0 = *matrix;
     scaled_font = mbe_scaled_font_create((mbe_font_face_t *)face,
-					   &font_matrix,
-					   &id, opt);
+					 matrix, &id);
 
     return (mb_scaled_font_t *)scaled_font;
 }
@@ -705,12 +594,9 @@
 static
 void test_query_font_face(void) {
     mb_font_face_t *face;
-    mbe_status_t status;
 
     face = query_font_face("serif", MB_FONT_SLANT_ROMAN, 100);
     CU_ASSERT(face != NULL);
-    status = mbe_font_face_status((mbe_font_face_t *)face);
-    CU_ASSERT(status == MBE_STATUS_SUCCESS);
     
     free_font_face(face);
 }
@@ -720,17 +606,12 @@
     co_aix matrix[6] = {5, 0, 0, 0, 5, 0};
     mb_font_face_t *face;
     mb_scaled_font_t *scaled;
-    mbe_status_t status;
 
     face = query_font_face("serif", MB_FONT_SLANT_ROMAN, 100);
     CU_ASSERT(face != NULL);
-    status = mbe_font_face_status((mbe_font_face_t *)face);
-    CU_ASSERT(status == MBE_STATUS_SUCCESS);
     
     scaled = make_scaled_font_face_matrix(face, matrix);
     CU_ASSERT(scaled != NULL);
-    status = mbe_scaled_font_status((mbe_scaled_font_t *)scaled);
-    CU_ASSERT(status == MBE_STATUS_SUCCESS);
     
     scaled_font_free(scaled);
     free_font_face(face);
--- a/src/shape_text.c	Sun Nov 08 00:37:29 2009 +0800
+++ b/src/shape_text.c	Wed Jun 09 17:30:09 2010 +0800
@@ -204,10 +204,7 @@
 }
 
 static int get_extents(sh_text_t *text, PangoRectangle *extents) {
-    mbe_matrix_t fmatrix;
-    mbe_matrix_t ctm;
     mbe_scaled_font_t *new_scaled;
-    mbe_font_options_t *fopt;
 
     pango_layout_get_extents(text->layout, NULL, extents);
     pango_extents_to_pixels(extents,NULL);