2008年11月18日 星期二

Microwindows with alpha blending support

Reference

http://hi.baidu.com/chenzhuoyou/blog/item/5ad45a3d9c057ceb3d6d97a2.html

http://hi.baidu.com/chenzhuoyou/blog/item/ee1f57607c7d5fdb8cb10d63.html

1.範例程式參考
src/demos/nanox/nxalpha.c

2.Patch microwindow-0.91

diff -Nur microwindows-0.91.org/src/demos/nanox/Makefile microwindows-0.91/src/demos/nanox/Makefile
--- microwindows-0.91.org/src/demos/nanox/Makefile    2008-11-17 20:36:13.000000000 +0800
+++ microwindows-0.91/src/demos/nanox/Makefile    2008-11-18 22:13:45.000000000 +0800
@@ -57,6 +57,7 @@
     $(MW_DIR_BIN)/ntetris \
     $(MW_DIR_BIN)/getselection \
     $(MW_DIR_BIN)/setselection \
+    $(MW_DIR_BIN)/nxalpha \
     $(MW_DIR_BIN)/dashdemo \
     $(MW_DIR_BIN)/pcfdemo \
     $(MW_DIR_BIN)/fontdemo \
diff -Nur microwindows-0.91.org/src/demos/nanox/nxalpha.c microwindows-0.91/src/demos/nanox/nxalpha.c
--- microwindows-0.91.org/src/demos/nanox/nxalpha.c    1970-01-01 08:00:00.000000000 +0800
+++ microwindows-0.91/src/demos/nanox/nxalpha.c    2008-11-19 13:20:49.000000000 +0800
@@ -0,0 +1,192 @@
+/* Alpha blending demo
+   By Jordan Crouse
+
+   This takes our favorite penguin and alpha blends him
+   against the background.  Hit the + and - keys to adjust the
+   alpha. 
+*/
+
+#include
+#include
+#include
+
+#define BGCOLOR GR_RGB(24, 125, 148)
+//#define BGCOLOR GR_RGB(0, 0, 0)
+
+int sw, sh;
+int iw = 91, ih = 100;
+
+int g_alpha = 128;
+GR_WINDOW_ID g_wid, g_pixmap, g_image;
+
+void do_alpha_blit(int x, int y, int w, int h, unsigned long mode) {
+
+  GR_GC_ID gc = GrNewGC();
+  GrSetGCForeground(gc, BGCOLOR);
+
+  /* Clear the holding buffer */
+  GrFillRect(g_pixmap, gc, 0, 0, w, h); 
+#if 0
+  /* Alpha blend the image in */
+  GrCopyArea(g_pixmap, gc, 0, 0, w, h, g_image, 0, 0, MWROP_SRCCOPY);
+
+  GrFillRect(g_pixmap, gc, 10, 10, 50, 50); 
+
+  GrCopyArea(g_pixmap, gc, 10, 10, 50, 50, g_image, 10, 10, mode);
+#endif
+#if 1
+  /* Alpha blend the image in */
+  GrCopyArea(g_pixmap, gc, 0, 0, w, h, g_image, 0, 0, mode);
+#endif
+  /* Copy the holding buffer to the screen */
+  GrCopyArea(g_wid, gc, x, y, w, h, g_pixmap, 0, 0, MWROP_SRCCOPY);
+  GrDestroyGC(gc);
+}
+
+void draw_window(int alpha) {
+
+  int xpos;
+
+  GR_GC_ID gc = GrNewGC();
+  GrSetGCForeground(gc, GR_RGB(255,255,255));
+  GrSetGCBackground(gc, BGCOLOR);
+  xpos = (sw - ((5 * iw) + 30)) / 2;
+
+  GrText(g_wid, gc, 5, 5, "Press + / - to change the alpha value", -1,
+     GR_TFTOP);
+
+  GrText(g_wid, gc, xpos, ((sh - ih) / 2) - 20, "Original", -1, 0);
+  GrCopyArea(g_wid, gc, xpos, (sh - ih) / 2, iw, ih, g_image,
+         0, 0, MWROP_SRCCOPY);
+
+  xpos += iw + 10;
+  
+  GrText(g_wid, gc, xpos, ((sh - ih) / 2) - 20, "Blend", -1, 0);
+  do_alpha_blit(xpos, (sh - ih) / 2, iw, ih, MWROP_BLEND | (alpha & 0xFF));
+
+  xpos += iw + 10;
+  
+  GrText(g_wid, gc, xpos, (sh - ih) / 2 - 20, "Add", -1, 0);
+  do_alpha_blit(xpos, (sh - ih) / 2, iw, ih, MWROP_BLENDADD | (alpha & 0xFF));
+   
+  xpos += iw + 10;
+  
+  GrText(g_wid, gc, xpos, (sh - ih) / 2 - 20, "Subtract", -1, 0);
+  do_alpha_blit(xpos, (sh - ih) / 2, iw, ih, MWROP_BLENDSUBTRACT | (alpha & 0xFF));
+   
+  xpos += iw + 10;
+
+  GrText(g_wid, gc, xpos, (sh - ih) / 2 - 20, "Reshade", -1, 0);
+  do_alpha_blit(xpos, (sh - ih) / 2, iw, ih, MWROP_BLENDRESHADE | (alpha & 0xFF));
+  
+  GrDestroyGC(gc);
+}
+
+void handle_events(GR_EVENT *event) {
+
+  switch(event->type) {
+  case GR_EVENT_TYPE_EXPOSURE:
+    draw_window(g_alpha);
+    break;
+
+  case GR_EVENT_TYPE_KEY_DOWN:
+    switch(event->keystroke.ch & 0x1) {
+    //case '=':
+    case 0:
+      g_alpha += 5;
+      if (g_alpha > 255) g_alpha = 255;
+      break;
+
+    //case '-':
+    case 1:
+      g_alpha -= 5;
+      if (g_alpha < 0) g_alpha = 0;
+      break;
+    }
+
+    printf("Alpha: %3.3d\r", g_alpha);
+    fflush(stdout);
+
+    draw_window(g_alpha);
+    break;
+
+  case GR_EVENT_TYPE_CLOSE_REQ:
+    exit(0);
+  }
+}
+
+int load_image(char *filename) {
+
+  GR_IMAGE_INFO iinfo;
+
+  GR_GC_ID gc = GrNewGC();
+  GR_IMAGE_ID image = GrLoadImageFromFile(filename, 0);
+
+  if (!image) return(-1);
+
+  GrGetImageInfo(image, &iinfo);
+
+  iw = iinfo.width;
+  ih = iinfo.height;
+
+  /* Make the pixmaps that will buffer the draw */
+  g_pixmap = GrNewPixmap(iw, ih, 0);
+  g_image = GrNewPixmap(iw, ih, 0);
+
+  GrSetGCForeground(gc, BGCOLOR);
+  GrFillRect(g_image, gc, 0, 0, iw, ih);
+
+  GrDrawImageToFit(g_image, gc, 0, 0, -1, -1, image);
+
+  GrDestroyGC(gc);
+  GrFreeImage(image);
+  return(0);
+}
+
+int main(int argc, char **argv) {
+
+  GR_SCREEN_INFO sinfo;
+
+  g_alpha = 128;
+
+  if (GrOpen() == -1) return(-1);

+  if (argc < 2) {
+    if(load_image("tux.gif") == -1) {
+      printf("Unable to open the image [tux.gif]\n");
+      GrClose();
+      return(-1);
+    }
+  }
+  else {
+    if (load_image(argv[1]) == -1) {
+      printf("Unable to open the image [%s]\n", argv[1]);
+      GrClose();
+      return(-1);
+    }
+  }
+
+  GrGetScreenInfo(&sinfo);
+
+  sw = sinfo.cols - 20;
+  sh = sinfo.rows - 20;
+
+  g_wid = GrNewWindow(GR_ROOT_WINDOW_ID,
+              10, 10, sw, sh, 0, BGCOLOR, 0);
+
+  GrSelectEvents(g_wid,
+         GR_EVENT_MASK_KEY_DOWN |
+         GR_EVENT_MASK_EXPOSURE |
+         GR_EVENT_MASK_CLOSE_REQ);
+
+  GrMapWindow(g_wid);

+  fflush(stdout);
+
+  while(1) {
+    GR_EVENT event;
+    GrGetNextEvent(&event);
+   
+    handle_events(&event);
+  }
+}
diff -Nur microwindows-0.91.org/src/drivers/fblin16.c microwindows-0.91/src/drivers/fblin16.c
--- microwindows-0.91.org/src/drivers/fblin16.c    2008-11-17 20:36:13.000000000 +0800
+++ microwindows-0.91/src/drivers/fblin16.c    2008-11-18 22:09:45.000000000 +0800
@@ -166,49 +166,90 @@
     src += srcx + srcy * slinelen;
 
 #if ALPHABLEND
-    if((op & MWROP_EXTENSION) != MWROP_BLENDCONSTANT)
-        goto stdblit;
+
+#define R_VAL(p) ((unsigned char *)(p))[2]
+#define G_VAL(p) ((unsigned char *)(p))[1]
+#define B_VAL(p) ((unsigned char *)(p))[0]
+
+#include
+
+    if((op & MWROP_EXTENSION) < MWROP_BLEND) goto stdblit;
     alpha = op & 0xff;
 
-    if (dstpsd->pixtype == MWPF_TRUECOLOR565) {
-        while(--h >= 0) {
-            for(i=0; i
-                unsigned int s = *src++;
-                unsigned int d = *dst;
-                unsigned int t = d & 0xf800;
-                unsigned int m1, m2, m3;
-                m1 = (((((s & 0xf800) - t)*alpha)>>8) & 0xf800) + t;
-                t = d & 0x07e0;
-                m2 = (((((s & 0x07e0) - t)*alpha)>>8) & 0x07e0) + t;
-                t = d & 0x001f;
-                m3 = (((((s & 0x001f) - t)*alpha)>>8) & 0x001f) + t;
-                *dst++ = m1 | m2 | m3;
-            }
-            dst += dlinelen - w;
-            src += slinelen - w;
-        }
+    if (dstpsd->pixtype == MWPF_TRUECOLOR565) {       /* 565 format */
+      while(--h >= 0) {
+        for(i=0; i
+          unsigned long tmp;
+
+          unsigned long in = (*src & 0xf800) << 8 | (*src & 0x07e0) << 5 | (*src & 0x001f) << 3;
+          unsigned long out = (*dst & 0xf800) << 8 | (*dst & 0x07e0) << 5 | (*dst & 0x001f) << 3;
+
+          unsigned long *ptr = &out;
+
+          switch (op & MWROP_EXTENSION) {
+          case MWROP_BLENDADD:
+        BLEND_ADD(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+       
+          case MWROP_BLENDSUBTRACT:
+        BLEND_SUB(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+       
+          case MWROP_BLENDRESHADE:
+        BLEND_RE(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+       
+          default:
+        BLEND(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+          }
+       
+          src++;
+          *dst++ = ((R_VAL(ptr) & 0xF8) << 8) | ((G_VAL(ptr) & 0xFC) << 3) | ((B_VAL(ptr) & 0xF8) >> 3);
+        }
+       
+        dst += dlinelen - w;
+        src += slinelen - w;
+      }
     } else {
-        /* 5/5/5 format*/
-        while(--h >= 0) {
-            for(i=0; i
-                unsigned int s = *src++;
-                unsigned int d = *dst;
-                unsigned int t = d & 0x7c00;
-                unsigned int m1, m2, m3;
-                m1 = (((((s & 0x7c00) - t)*alpha)>>8) & 0x7c00) + t;
-                t = d & 0x03e0;
-                m2 = (((((s & 0x03e0) - t)*alpha)>>8) & 0x03e0) + t;
-                t = d & 0x001f;
-                m3 = (((((s & 0x001f) - t)*alpha)>>8) & 0x001f) + t;
-                *dst++ = m1 | m2 | m3;
-            }
-            dst += dlinelen - w;
-            src += slinelen - w;
-        }
+     
+      while(--h >= 0) {
+        for(i=0; i
+          unsigned long tmp;
+
+          unsigned long in = (*src & 0x7c00) << 9 | (*src & 0x03e0) << 6 | (*src & 0x001f) << 3;
+          unsigned long out = (*dst & 0x7c00) << 9 | (*dst & 0x03e0) << 6 | (*dst & 0x001f) << 3;
+   
+          unsigned long *ptr = &out;
+
+          switch (op & MWROP_EXTENSION) {
+          case MWROP_BLENDADD:
+        BLEND_ADD(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+       
+          case MWROP_BLENDSUBTRACT:
+        BLEND_SUB(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+       
+          case MWROP_BLENDRESHADE:
+        BLEND_RE(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+       
+          default:
+        BLEND(R_VAL(&in), G_VAL(&in), B_VAL(&in), alpha, ptr);
+        break;
+          }
+          src++;
+          *dst++ = ((R_VAL(ptr) & 0xF8) << 7) | ((G_VAL(ptr) & 0xF8) << 2) | ((B_VAL(ptr) & 0xF8) >> 3);
+        }
+       
+        dst += dlinelen - w;
+        src += slinelen - w;
+      }
     }
     DRAWOFF;
     return;
-stdblit:
+ stdblit:
 #endif
 
     if (op == MWROP_COPY) {
diff -Nur microwindows-0.91.org/src/drivers/fblin24.c microwindows-0.91/src/drivers/fblin24.c
--- microwindows-0.91.org/src/drivers/fblin24.c    2008-11-17 20:36:13.000000000 +0800
+++ microwindows-0.91/src/drivers/fblin24.c    2008-11-18 22:09:45.000000000 +0800
@@ -172,25 +172,45 @@
     src += (srcx + srcy * srcpsd->linelen) * 3;
 
 #if ALPHABLEND
-    if((op & MWROP_EXTENSION) != MWROP_BLENDCONSTANT)
+#define R_VAL(p) ((unsigned char *)(p))[2]
+#define G_VAL(p) ((unsigned char *)(p))[1]
+#define B_VAL(p) ((unsigned char *)(p))[0]
+
+#include
+
+    if((op & MWROP_EXTENSION) < MWROP_BLEND)
         goto stdblit;
     alpha = op & 0xff;
-
+   
     while(--h >= 0) {
-        for(i=0; i
-            unsigned long s = *src++;
-            unsigned long d = *dst;
-            *dst++ = (unsigned char)(((s - d)*alpha)>>8) + d;
-            s = *src++;
-            d = *dst;
-            *dst++ = (unsigned char)(((s - d)*alpha)>>8) + d;
-            s = *src++;
-            d = *dst;
-            *dst++ = (unsigned char)(((s - d)*alpha)>>8) + d;
-        }
-        dst += dlinelen_minus_w;
-        src += slinelen_minus_w;
+      for(i=0; i
+        unsigned long tmp;
+
+        switch (op & MWROP_EXTENSION) {
+        case MWROP_BLENDADD:
+          BLEND_ADD(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+          break;
+        case MWROP_BLENDSUBTRACT:
+          BLEND_SUB(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+          break;
+         
+        case MWROP_BLENDRESHADE:
+          BLEND_RE(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+          break;
+           
+        default:
+          BLEND(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+          break;
+        }
+       
+        src++;
+        dst++;
+      }
+     
+      dst += dlinelen_minus_w;
+      src += slinelen_minus_w;
     }
+   
     DRAWOFF;
     return;
 stdblit:
diff -Nur microwindows-0.91.org/src/drivers/fblin32.c microwindows-0.91/src/drivers/fblin32.c
--- microwindows-0.91.org/src/drivers/fblin32.c    2008-11-17 20:36:13.000000000 +0800
+++ microwindows-0.91/src/drivers/fblin32.c    2008-11-19 13:36:20.000000000 +0800
@@ -119,14 +119,12 @@
 linear32_blit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD w, MWCOORD h,
     PSD srcpsd, MWCOORD srcx, MWCOORD srcy, long op)
 {
-    ADDR8    dst8, src8;
     ADDR32    dst = dstpsd->addr;
     ADDR32    src = srcpsd->addr;
     int    i;
     int    dlinelen = dstpsd->linelen;
     int    slinelen = srcpsd->linelen;
-    int    dlinelen_minus_w4;
-    int    slinelen_minus_w4;
+
 #if ALPHABLEND
     unsigned int alpha;
 #endif
@@ -149,35 +147,44 @@
     src += srcx + srcy * slinelen;
 
 #if ALPHABLEND
-    if((op & MWROP_EXTENSION) != MWROP_BLENDCONSTANT)
-        goto stdblit;
-    alpha = op & 0xff;
-
-    src8 = (ADDR8)src;
-    dst8 = (ADDR8)dst;
-    dlinelen_minus_w4 = (dlinelen - w) * 4;
-    slinelen_minus_w4 = (slinelen - w) * 4;
-    while(--h >= 0) {
-        for(i=0; i
-            /* FIXME: This doesn't look endian-neutral.
-             * I don't think this'll work on PowerPC,
-             * but I don't have one to test it.
-             */
-            register unsigned long s = *src8++;
-            register unsigned long d = *dst8;
-            *dst8++ = (unsigned char)(((s - d)*alpha)>>8) + d;
-            s = *src8++;
-            d = *dst8;
-            *dst8++ = (unsigned char)(((s - d)*alpha)>>8) + d;
-            s = *src8;
-            d = *dst8;
-            *dst8 = (unsigned char)(((s - d)*alpha)>>8) + d;
-            dst8 += 2;
-            src8 += 2;
-        }
-        dst8 += dlinelen_minus_w4;
-        src8 += slinelen_minus_w4;
-    }
+
+  #define R_VAL(p) ((unsigned char *)(p))[2]
+  #define G_VAL(p) ((unsigned char *)(p))[1]
+  #define B_VAL(p) ((unsigned char *)(p))[0]

+  #include

+        if((op & MWROP_EXTENSION) < MWROP_BLEND)goto stdblit;
+        alpha = op & 0xff;

+        while(--h >= 0) {
+          for(i=0; i
+            unsigned long tmp;

+            switch (op & MWROP_EXTENSION) {
+            case MWROP_BLENDADD:
+              BLEND_ADD(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+              break;
+            case MWROP_BLENDSUBTRACT:
+              BLEND_SUB(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+              break;

+            case MWROP_BLENDRESHADE:
+              BLEND_RE(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+              break;

+            default:
+              BLEND(R_VAL(src), G_VAL(src), B_VAL(src), alpha, dst);
+              break;
+            }

+            src++;
+            dst++;
+          }

+          dst += dlinelen - w;
+          src += slinelen - w;
+        }
     DRAWOFF;
     return;
 stdblit:
diff -Nur microwindows-0.91.org/src/drivers/fblin8.c microwindows-0.91/src/drivers/fblin8.c
--- microwindows-0.91.org/src/drivers/fblin8.c    2008-11-17 20:36:13.000000000 +0800
+++ microwindows-0.91/src/drivers/fblin8.c    2008-11-18 22:09:45.000000000 +0800
@@ -19,6 +19,11 @@
 #include "device.h"
 #include "fb.h"
 
+/* FIXME:  This table lookup does not scale well
+   We now have 4 alpha blending modes, which would result in 256 * 256 * 4 entries
+   which IMHO is not acceptable.  This needs to be re thought
+*/
+
 #if ALPHABLEND
 /*
  * Alpha lookup tables for 256 color palette systems
@@ -164,37 +169,86 @@
     src = ((ADDR8)srcpsd->addr) + srcx + srcy * slinelen;
 
 #if ALPHABLEND
-    if((op & MWROP_EXTENSION) != MWROP_BLENDCONSTANT)
+
+#define R_VAL(p) ((unsigned char *)(p))[2]
+#define G_VAL(p) ((unsigned char *)(p))[1]
+#define B_VAL(p) ((unsigned char *)(p))[0]
+   
+#include
+
+    if((op & MWROP_EXTENSION) < MWROP_BLEND)
         goto stdblit;
     srcalpha = op & 0xff;
 
     /* FIXME create lookup table after palette is stabilized...*/
-    if(!rgb_to_palindex || !alpha_to_rgb) {
-        init_alpha_lookup();
-        if(!rgb_to_palindex || !alpha_to_rgb)
-            goto stdblit;
-    }
+    /* We should only do this for palette mode - truecolor 332
+       can compute it on the fly */
 
-    /* Create 5 bit alpha value index for 256 color indexing*/
-
-    /* destination alpha is (1 - source) alpha*/
-    dstalpha = ((srcalpha>>3) ^ 31) << 8;
-    srcalpha = (srcalpha>>3) << 8;
-
-    while(--h >= 0) {
+    if (dstpsd->pixtype == MWPF_PALETTE) {
+      if(!rgb_to_palindex || !alpha_to_rgb) {
+        init_alpha_lookup();
+        if(!rgb_to_palindex || !alpha_to_rgb)
+          goto stdblit;
+      }
+
+      /* Create 5 bit alpha value index for 256 color indexing*/
+     
+      /* destination alpha is (1 - source) alpha*/
+      dstalpha = ((srcalpha>>3) ^ 31) << 8;
+      srcalpha = (srcalpha>>3) << 8;
+     
+      while(--h >= 0) {
         int    i;
         for(i=0; i
-        /* Get source RGB555 value for source alpha value*/
-        unsigned short s = alpha_to_rgb[srcalpha + *src++];
+          /* Get source RGB555 value for source alpha value*/
+          unsigned short s = alpha_to_rgb[srcalpha + *src++];
+         
+          /* Get destination RGB555 value for dest alpha value*/
+          unsigned short d = alpha_to_rgb[dstalpha + *dst];
+         
+          /* Add RGB values together and get closest palette index to it*/
+          *dst++ = rgb_to_palindex[s + d];
+        }
+        dst += dlinelen - w;
+        src += slinelen - w;
+      }
+    }
+    else { /* Truecolor 332 mode */
+      unsigned long tmp;
+
+      while(--h >= 0) {
+        int i;
+        for(i=0; i
+          unsigned long in = (*src & 0xE0) << 16 | (*src & 0x16) << 11 | (*src & 0x03) << 6;
+          unsigned long out = (*dst & 0xE0) << 16 | (*dst & 0x16) << 11 | (*dst & 0x03) << 6;
 
-        /* Get destination RGB555 value for dest alpha value*/
-        unsigned short d = alpha_to_rgb[dstalpha + *dst];
+          unsigned long *ptr = &out;
 
-        /* Add RGB values together and get closest palette index to it*/
-        *dst++ = rgb_to_palindex[s + d];
+          switch (op & MWROP_EXTENSION) {
+          case MWROP_BLENDADD:
+        BLEND_ADD(R_VAL(&in), G_VAL(&in), B_VAL(&in), srcalpha, ptr);
+        break;
+       
+          case MWROP_BLENDSUBTRACT:
+        BLEND_SUB(R_VAL(&in), G_VAL(&in), B_VAL(&in), srcalpha, ptr);
+        break;
+       
+          case MWROP_BLENDRESHADE:
+        BLEND_RE(R_VAL(&in), G_VAL(&in), B_VAL(&in), srcalpha, ptr);
+        break;
+       
+          default:
+        BLEND(R_VAL(&in), G_VAL(&in), B_VAL(&in), srcalpha, ptr);
+        break;
+          }
+         
+          src++;
+          *dst++ = ((R_VAL(ptr) & 0x07) << 5) | ((G_VAL(ptr) & 0x07) << 2) | (B_VAL(ptr) & 0x03);
         }
+       
         dst += dlinelen - w;
         src += slinelen - w;
+      }
     }
     DRAWOFF;
     return;
diff -Nur microwindows-0.91.org/src/include/alpha.h microwindows-0.91/src/include/alpha.h
--- microwindows-0.91.org/src/include/alpha.h    1970-01-01 08:00:00.000000000 +0800
+++ microwindows-0.91/src/include/alpha.h    2008-11-18 22:09:45.000000000 +0800
@@ -0,0 +1,296 @@
+/*
+ * Copied and inspired by imlib2/src/blend.h
+ * most routines by Raster (raster@rasterman.com).
+ *
+ * IMBLIB2 Copyright (C) 1999 Carsten Haitzler and various contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software, its documentation and marketing & publicity
+ * materials, and acknowledgment shall be given in the documentation, materials
+ * and software packages that this Software was used.
+ */
+
+/* I have included Rasters excellent comments at the bottom of this file.  These
+   routines and alogrithms are his.  Thank you so much Raster (and special props to Chris Ross,
+   who pointed these out to me).  The only changes I made are to refect the fact that we don't
+   currently have a alpha channel, so we don't need to worry about merging / saturating the
+   destination alpha channel.
+*/
+
+/* Note:  The macros R_VAL, G_VAL and B_VAL need to be defined for the appropriate depth */
+
+#if !defined(R_VAL) || !defined(G_VAL) || !defined(B_VAL)
+#error You have to define R_VAL, G_VAL and B_VAL for your depth
+#endif
+
+/* Saturate values in the range [0, 512) */
+#define SATURATE_UPPER(nc, v) nc = ((v) | (-((v) >> 8)))
+
+/* Saturate values in the range (-256, 256) */
+#define SATURATE_LOWER(nc, v) nc = (v) & (~((v) >> 8))
+
+/* Saturate values in the range (-256, 512) */
+#define SATURATE_BOTH(nc, v) nc = ((v) | (-((v) >> 8))) & (~((v) >> 9))
+
+#define BLEND_COLOR(a, nc, c, cc) \
+tmp = ((c) - (cc)) * (a); \
+nc = (cc) + ((tmp + (tmp >> 8) + 0x80) >> 8);
+
+#define ADD_COLOR_WITH_ALPHA(a, nc, c, cc) \
+tmp = (cc) + (((c) * (a)) >> 8); \
+SATURATE_UPPER(nc, tmp);
+
+#define ADD_COLOR(nc, c, cc) \
+tmp = (cc) + (c); \
+SATURATE_UPPER(nc, tmp);
+
+#define SUB_COLOR_WITH_ALPHA(a, nc, c, cc) \
+tmp = (cc) - (((c) * (a)) >> 8); \
+SATURATE_LOWER((nc), (tmp));
+
+#define SUB_COLOR(nc, c, cc) \
+tmp = (cc) - (c); \
+SATURATE_LOWER(nc, tmp);
+
+#define RESHADE_COLOR_WITH_ALPHA(a, nc, c, cc) \
+tmp = (cc) + ((((c) - 127) * (a)) >> 7); \
+SATURATE_BOTH(nc, tmp);
+
+#define RESHADE_COLOR(nc, c, cc) \
+tmp = (cc) + (((c) - 127) << 1); \
+SATURATE_BOTH(nc, tmp);
+
+#define BLEND(r1, g1, b1, a1, dest) \
+BLEND_COLOR(a1, R_VAL(dest), r1, R_VAL(dest)); \
+BLEND_COLOR(a1, G_VAL(dest), g1, G_VAL(dest)); \
+BLEND_COLOR(a1, B_VAL(dest), b1, B_VAL(dest));
+
+#define BLEND_ADD(r1, g1, b1, a1, dest) \
+ADD_COLOR_WITH_ALPHA(a1, R_VAL(dest), r1, R_VAL(dest)); \
+ADD_COLOR_WITH_ALPHA(a1, G_VAL(dest), g1, G_VAL(dest)); \
+ADD_COLOR_WITH_ALPHA(a1, B_VAL(dest), b1, B_VAL(dest));
+
+#define BLEND_SUB(r1, g1, b1, a1, dest) \
+SUB_COLOR_WITH_ALPHA(a1, R_VAL(dest), r1, R_VAL(dest)); \
+SUB_COLOR_WITH_ALPHA(a1, G_VAL(dest), g1, G_VAL(dest)); \
+SUB_COLOR_WITH_ALPHA(a1, B_VAL(dest), b1, B_VAL(dest));
+
+#define BLEND_RE(r1, g1, b1, a1, dest) \
+RESHADE_COLOR_WITH_ALPHA(a1, R_VAL(dest), r1, R_VAL(dest)); \
+RESHADE_COLOR_WITH_ALPHA(a1, G_VAL(dest), g1, G_VAL(dest)); \
+RESHADE_COLOR_WITH_ALPHA(a1, B_VAL(dest), b1, B_VAL(dest));
+
+/*
+ * 1) Basic Saturation - 8 bit unsigned
+ *
+ * The add, subtract, and reshade operations generate new color values that may
+ * be out of range for an unsigned 8 bit quantity.  Therefore, we will want to
+ * saturate the values into the range [0, 255].  Any value < 0 will become 0,
+ * and any value > 255 will become 255.  Or simply:
+ *
+ *   saturated = (value < 0) ? 0 : ((value > 255) ? 255 : value)
+ *
+ * Of course the above isn't the most efficient means of saturating.  Sometimes
+ * due to the nature of a calculation, we know we only need to saturate from
+ * above (> 255) or just from below (< 0).  Or simply:
+ *
+ *   saturated = (value < 0)   ?   0 : value
+ *   saturated = (value > 255) ? 255 : value
+ *
+ * 2) Alternate Forms of Saturation
+ *
+ * The methods of saturation described above use testing/branching operations,
+ * which are not necessarily efficient on all platforms.  There are other means
+ * of performing saturation using just simple arithmetic operations
+ * (+, -, >>, <<, ~).  A discussion of these saturation techniques follows.
+ *
+ * A) Saturation in the range [0, 512), or "from above".
+ *
+ * Assuming we have an integral value in the range [0, 512), the following
+ * formula evaluates to either 0, or 255:
+ *
+ *    (value & 255) - ((value & 256) >> 8)
+ *
+ * This is easy to show.  Notice that if the value is in the range [0, 256)
+ * the 9th bit is 0, and we get (0 - 0), which is 0.   And if the value is in
+ * the range [256, 512) the 9th bit is 1, and we get (256 - 1), which is 255.
+ *
+ * Now, using the above information and the fact that assigning an integer to
+ * an 8 bit unsigned value will truncate to the lower 8 bits of the integer,
+ * the following properly saturates:
+ *
+ *    8bit_value = value | (value & 256) - ((value & 256) >> 8)
+ *
+ * To prove this to yourself, just think about what the lower 8 bits look like
+ * in the ranges [0, 256) and [256, 512).  In particular, notice that the value
+ * in the range [0, 256) are unchanged, and values in the range [256, 512)
+ * always give you 255.  Just what we want!
+ *
+ * B) Saturation in the range (-256, 256), or "from below".
+ *
+ * Assuming we have an integral value in the range (-256, 256), the following
+ * formula evaluates to either 0, or -1:
+ *
+ *   ~(value >> 8)
+ *
+ * Here's why.  If the value is in the range [0, 256), then shifting right by
+ * 8 bits gives us all 0 bits, or 0.  And thus inverting the bits gives all
+ * 1 bits, which is -1.  If the value is in the range (-256, 0), then the 9th
+ * bit and higher bits are all 1.  So, when we shift right by 8 bits (with
+ * signed extension), we get a value with all 1 bits.  Which when inverted is
+ * all 0 bits, or 0.
+ *
+ * Now, using the above information the following properly saturates:
+ *
+ *    8bit_value = value & (~(value >> 8))
+ *
+ * To prove this to yourself, noticed that values in the range (-256, 0) will
+ * always be AND'd with 0, and thus map to 0.   Further, values in the range
+ * [0, 256) will always be AND'd with a value that is all 1 bits, and thus
+ * be unchanged.  Just what we want!
+ *
+ * C) Saturation in the range (-256, 512), or "from above and below".
+ *
+ * The short of it is the following works:
+ *
+ *    8bit_value = (tmp | ((tmp & 256) - ((tmp & 256) >> 8))) & (~(tmp >> 9))
+ *
+ * We leave it to the reader to prove.  Looks very similar to the techniques
+ * used above, eh? :)
+ */
+  
+/*
+ * 1) Operations
+ *
+ * There are 4 operations supported:
+ *
+ *    Copy, Add, Subtract, and Reshade
+ *
+ * For each operation there are 3 different variations that can be made:
+ *
+ *   a) Use "blend" or "copy" in the calculations?  A "blend" uses the alpha
+ *      value of the source pixel to lighten the source pixel values.  Where
+ *      as "copy" ignores the alpha value and uses the raw source pixel values.
+ *   b) Include source alpha in the calculation for new destination alpha?
+ *      If source alpha is not used, then destination alpha is preserved.
+ *      If source alpha is used, a "copy" sets the new alpha to the source
+ *      alpha, and a "blend" adds them together (with saturation).
+ *   c) Should the source pixels be passed through a color modifier before the
+ *      calculations are performed?
+ *
+ * All together we have 4*2*2*2 = 32 combinations.
+ *
+ * 2) Copy operation
+ *
+ * The "copy" version of this operation copies the source image onto the
+ * destination image.
+ *
+ * The "blend" version of this operation blends the source image color 'c' with
+ * the destination image color 'cc' using 'a' (in the range [0, 1]) according
+ * to the following formula.  Also notice that saturation is not needed for
+ * this calculation, the output is in the range [0, 255]:
+ *
+ *    nc = c * alpha + (1 - alpha) * cc
+ *       = c * alpha - cc * alpha + cc
+ *       = (c - cc) * alpha + cc;
+ *
+ * A discussion of how we're calculating this value follows:
+ *
+ * We're using 'a', an integer, in the range [0, 255] for alpha (and for 'c'
+ * and 'cc', BTW).  Therefore, we need to slightly modify the equation to take
+ * that into account.  To get into the range [0, 255] we need to divide 'a'
+ * by 255:
+ *
+ *    nc = ((c - cc) * a) / 255 + cc
+ *
+ * Notice that it is faster to divide by 256 (bit shifting), however without a
+ * fudge factor 'x' to balance things this isn't horribly accurate.  So, let's
+ * solve for 'x'.  The equality is:
+ *
+ *    ((c - cc) * a) / 256 + cc + x = ((c - cc) * a) / 255 + cc
+ *
+ * The 'cc' terms cancel, and multiply both sides by 255*256 to remove the
+ * fractions:
+ *
+ *    ((c - cc) * a) * 255 + 255 * 256 * x = ((c - cc) * a) * 256
+ *
+ * Get the 'x' term alone:
+ *
+ *    255 * 256 * x = ((c - cc) * a)
+ *
+ * Divide both sides by 255 * 256 to solve for 'x':
+ *
+ *    x = ((c - cc) * a) / (255 * 256)
+ *
+ * And putting 'x' back into the equation we get:
+ *
+ *    nc = ((c - cc) * a) / 256 + cc + ((c - cc) * a) / (255 * 256)
+ *
+ * And if we let 'tmp' represent the value '(c - cc) * a', and do a little
+ * regrouping we get:
+ *
+ *    nc = tmp / 256 + tmp / (255 * 256) + cc
+ *       = (tmp + tmp / 255) / 256 + cc
+ *
+ * We'll be using integer arithmetic, and over the range of values tmp takes
+ * (in [-255*255, 255*255]) the term tmp/(255*256) is pretty much the same as
+ * tmp/(256*256).  So we get:
+ *
+ *    nc = (tmp + tmp / 256) / 256 + cc
+ *
+ * And because the division of the sum uses integer arithmetic, it always
+ * rounds up/down even if that isn't the "best" choice.  If we add .5 to the
+ * sum, we can get standard rounding:  Like so:
+ *
+ *    nc = (tmp + tmp / 256 + 128) / 256 + cc
+ *
+ * 3) Add operation
+ *
+ * The "copy" version of this operation sums the source image pixel values
+ * with the destination image pixel values, saturating at 255 (from above).
+ *
+ * The "blend" version of this operation sums the source image pixel values,
+ * after taking into account alpha transparency (e.g. a percentage), with the
+ * destination image pixel values, saturating at 255 (from above).
+ *
+ * 4) Subtract operation
+ *
+ * This operation is the same as the Add operation, except the source values
+ * are subtracted from the destination values (instead of added).  Further,
+ * the result must be saturated at 0 (from below).
+ *
+ * 5) Reshade operation
+ *
+ * This operation uses the source image color values to lighten/darken color
+ * values in the destination image using the following formula:
+ *
+ *    nc = cc + ((c - middle_value) * 2 * alpha)
+ *
+ * Recall our pixel color and alpha values are in the range [0, 255].  So, the
+ * "blend" version of this operation can be calculated as:
+ *
+ *    nc = cc + ((c - 127) * 2 * (a / 255))
+ *
+ * And in an integer arithmetic friendly form is:
+ *
+ *    nc = cc + (((c - 127) * a) >> 7)
+ *
+ * The "copy" version of this operation treats alpha as 1.0 (or a/255), and in
+ * integer arithmetic friendly form is:
+ *
+ *    nc = cc + ((c - 127) << 1)
+ *
+ * Notice the color values created by this operation are in the range
+ * (-256, 512), and thus must be saturated at 0 and 255 (from above and below).
+ */
+
+
+
+
diff -Nur microwindows-0.91.org/src/include/mwtypes.h microwindows-0.91/src/include/mwtypes.h
--- microwindows-0.91.org/src/include/mwtypes.h    2008-11-17 20:36:14.000000000 +0800
+++ microwindows-0.91/src/include/mwtypes.h    2008-11-18 22:28:44.000000000 +0800
@@ -132,7 +132,7 @@
 #define MWROP_SRCTRANSCOPY    0x21000000L
 
 /* alpha blend src -> dst with constant alpha, alpha value in low 8 bits*/
-#define MWROP_BLENDCONSTANT    0x22000000L
+/*#define MWROP_BLENDCONSTANT    0x22000000L*/
 
 /* alpha blend fg/bg color -> dst with src as alpha channel*/
 #define MWROP_BLENDFGBG        0x23000000L
@@ -143,6 +143,18 @@
 /* stretch src -> dst*/
 #define MWROP_STRETCH        0x25000000L
 
+ /* alpha blend src & dst with constant alpha, alpha value in low 8 bits*/
+
+#define MWROP_BLEND         0x26000000L
+#define MWROP_BLENDCONSTANT     MWROP_BLEND
+
+/* alpha blend src + dst with constant alpha, alpha value in low 8 bits */
+#define MWROP_BLENDADD          0x27000000L
+/* alpha blend src - dst with constant alpha, alpha value in low 8 bits */
+#define MWROP_BLENDSUBTRACT     0x28000000L
+/* Use src to lighten / darken dst value, alpha value in low 8 bits */
+#define MWROP_BLENDRESHADE      0x29000000L
+
 /* Use the MWMODE value in the graphics context
  * to choose the appropriate MWROP value.
  * (This is only valid in calls to the Nano-X API,


2008年11月16日 星期日

Microwindow 中文顯示 with pcf fonts

相關連結

Unicode Code Converter
http://rishida.net/scripts/uniview/conversion.php

http://space.flash8.net/space/?638324/action_viewspace_itemid_374138.html


字型使用 fireflyR16.pcf

fonts.dir

1
fireflyR16.pcf -firefly-sung-medium-r-normal--16-150-75-75-p-159-iso10646-1

要顯示firefly字型,需要作UTF-8 to ISO10646-1
也就是 UTF-8 to Unicode (UCS-2)

Microwindow 中相關的檔案

src/config
src/engine/devfont.c
src/engine/font_pcf.c

1.src/config

####################################################################
# PCF font support
# Selecting HAVE_PCFGZ_SUPPORT will allow you to directly read
# .pcf.gz files, but it will add libz to the size of the server
####################################################################
HAVE_PCF_SUPPORT         = Y
HAVE_PCFGZ_SUPPORT       = N
PCF_FONT_DIR             = "/phone/lib/X11/fonts/misc"

不知道為何gziped pcf font在我的系統中讀到的資料是不正確的.
應該跟gzopen, gzread, gzseek, gzclose有關.所以不支援囉.

注意!!!PCF_FONT_DIR要正確設定到PCF字型所在的路徑

2.src/engine/devfont.c

關於轉碼的部份在
int GdConvertEncoding(const void *istr, MWTEXTFLAGS iflags, int cc, void *ostr,
    MWTEXTFLAGS oflags)

看起來是有支援UTF-8 to Unicode, 實際上轉出來的碼是不正確的

3.src/engine/font_pcf.c

參考
http://tw.myblog.yahoo.com/stevegigijoe/article?mid=55&prev=56&next=54

4.UTF-8 to UCS-2

/* Set to 1 to turn bad UTF8 bytes into ISO-8859-1. If this is to zero
   they are instead turned into the Unicode REPLACEMENT CHARACTER, of
   value 0xfffd.
   If this is on utf8decode will correctly map most (perhaps all)
   human-readable text that is in ISO-8859-1. This may allow you
   to completely ignore character sets in your code because virtually
   everything is either ISO-8859-1 or UTF-8.
*/
#define ERRORS_TO_ISO8859_1 1

/* Set to 1 to turn bad UTF8 bytes in the 0x80-0x9f range into the
   Unicode index for Microsoft's CP1252 character set. You should
   also set ERRORS_TO_ISO8859_1. With this a huge amount of more
   available text (such as all web pages) are correctly converted
   to Unicode.
*/
#define ERRORS_TO_CP1252 1

/* A number of Unicode code points are in fact illegal and should not
   be produced by a UTF-8 converter. Turn this on will replace the
   bytes in those encodings with errors. If you do this then converting
   arbitrary 16-bit data to UTF-8 and then back is not an identity,
   which will probably break a lot of software.
*/
#define STRICT_RFC3629 0

#if ERRORS_TO_CP1252
// Codes 0x80..0x9f from the Microsoft CP1252 character set, translated
// to Unicode:
static unsigned short cp1252[32] = {
  0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
  0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
  0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
  0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178
};
#endif

/*! Decode a single UTF-8 encoded character starting at \e p. The
    resulting Unicode value (in the range 0-0x10ffff) is returned,
    and \e len is set the the number of bytes in the UTF-8 encoding
    (adding \e len to \e p will point at the next character).

    If \a p points at an illegal UTF-8 encoding, including one that
    would go past \e end, or where a code is uses more bytes than
    necessary, then *(unsigned char*)p is translated as though it is
    in the Microsoft CP1252 character set and \e len is set to 1.
    Treating errors this way allows this to decode almost any
    ISO-8859-1 or CP1252 text that has been mistakenly placed where
    UTF-8 is expected, and has proven very useful.

    If you want errors to be converted to error characters (as the
    standards recommend), adding a test to see if the length is
    unexpectedly 1 will work:

\code
    if (*p & 0x80) { // what should be a multibyte encoding
      code = utf8decode(p,end,&len);
      if (len<2) code = 0xFFFD; // Turn errors into REPLACEMENT CHARACTER
    } else { // handle the 1-byte utf8 encoding:
      code = *p;
      len = 1;
    }
\endcode

    Direct testing for the 1-byte case (as shown above) will also
    speed up the scanning of strings where the majority of characters
    are ASCII.
*/
unsigned utf8decode(const char* p, const char* end, int* len)
{
  unsigned char c = *(unsigned char*)p;
  if (c < 0x80) {
    *len = 1;
    return c;
#if ERRORS_TO_CP1252
  } else if (c < 0xa0) {
    *len = 1;
    return cp1252[c-0x80];
#endif
  } else if (c < 0xc2) {
    goto FAIL;
  }
  if (p+1 >= end || (p[1]&0xc0) != 0x80) goto FAIL;
  if (c < 0xe0) {
    *len = 2;
    return
      ((p[0] & 0x1f) << 6) +
      ((p[1] & 0x3f));
  } else if (c == 0xe0) {
    if (((unsigned char*)p)[1] < 0xa0) goto FAIL;
    goto UTF8_3;
#if STRICT_RFC3629
  } else if (c == 0xed) {
    // RFC 3629 says surrogate chars are illegal.
    if (((unsigned char*)p)[1] >= 0xa0) goto FAIL;
    goto UTF8_3;
  } else if (c == 0xef) {
    // 0xfffe and 0xffff are also illegal characters
    if (((unsigned char*)p)[1]==0xbf &&
  ((unsigned char*)p)[2]>=0xbe) goto FAIL;
    goto UTF8_3;
#endif
  } else if (c < 0xf0) {
  UTF8_3:
    if (p+2 >= end || (p[2]&0xc0) != 0x80) goto FAIL;
    *len = 3;
    return
      ((p[0] & 0x0f) << 12) +
      ((p[1] & 0x3f) << 6) +
      ((p[2] & 0x3f));
  } else if (c == 0xf0) {
    if (((unsigned char*)p)[1] < 0x90) goto FAIL;
    goto UTF8_4;
  } else if (c < 0xf4) {
  UTF8_4:
    if (p+3 >= end || (p[2]&0xc0) != 0x80 || (p[3]&0xc0) != 0x80) goto FAIL;
    *len = 4;
#if STRICT_RFC3629
    // RFC 3629 says all codes ending in fffe or ffff are illegal:
    if ((p[1]&0xf)==0xf &&
  ((unsigned char*)p)[2] == 0xbf &&
  ((unsigned char*)p)[3] >= 0xbe) goto FAIL;
#endif
    return
      ((p[0] & 0x07) << 18) +
      ((p[1] & 0x3f) << 12) +
      ((p[2] & 0x3f) << 6) +
      ((p[3] & 0x3f));
  } else if (c == 0xf4) {
    if (((unsigned char*)p)[1] > 0x8f) goto FAIL; // after 0x10ffff
    goto UTF8_4;
  } else {
  FAIL:
    *len = 1;
#if ERRORS_TO_ISO8859_1
    return c;
#else
    return 0xfffd; // Unicode REPLACEMENT CHARACTER
#endif
  }
}

typedef struct {                /* normal 16 bit characters are two bytes */
    unsigned char byte1;
    unsigned char byte2;
} XChar2b;

////////////////////////////////////////////////////////////////
// Things you can do once the font+size has been selected:

// I see no sign of "FontSets" working. Instead this supposedly will
// draw the correct letters if you happen to pick an iso10646-1 font.

// This is similar to utf8towc() but works with the big-endian-only
// structure X seems to want, and does not bother with surrogate
// pairs.  If all characters are 1 byte or errors it returns
// null. Otherwise it converts it to 16-bit and returns the allocated
// buffer and size:
static XChar2b* utf8to2b(const char* text, int n, int* charcount) {
 
  static XChar2b* buffer = 0;
  static int bufcount = 0;

  const char* p = text;
  const char* e = text+n;
  int sawutf8 = 0;
  int count = 0;
  while (p < e) {
    if (*(unsigned char*)p < 0x80) p++; // ascii
    else if (*(unsigned char*)p < 0xa0) {sawutf8 = 1; p++;} //cp1252
    else if (*(unsigned char*)p < 0xC2) p++; // other bad code
    else {
      int len; utf8decode(p,e,&len);
      if (len > 1) sawutf8 = 1;
      else if (!len) len = 1;
      p += len;
    }
    count++;
  }
  if (!sawutf8) return 0;
  *charcount = count;
  if(bufcount < count)  {
    bufcount = count;
    if(buffer)
      free(buffer);
    buffer = malloc(sizeof(XChar2b)*count);
  } else if(buffer)
    memset(buffer, 0, sizeof(XChar2b)*count);

  count = 0;
  p = text;
  while (p < e) {
    unsigned char c = *(unsigned char*)p;
    if (c < 0xC2) { // ascii letter or bad code
      buffer[count].byte1 = 0;
      buffer[count].byte2 = c;
      p++;
    } else {
      int len;
      unsigned n = utf8decode(p,e,&len);
      if (n > 0xffff) n = '?';
      p += len;
      buffer[count].byte1 = n>>8;
      buffer[count].byte2 = n;
    }
    count++;
  }
  return buffer;
}

5.實際測試
 
  int count = 0;
  unsigned char buffer[512];

  strcpy(buffer, "測試在Microwindow中顯示PCF字型");
  XChar2b *uc16 = utf8to2b(buffer, strlen(buffer), &count);
  GrText(main_wid, gc, 0, 0, uc16, count, GR_TFXCHAR2B|GR_TFBASELINE);